<commit_before>//     Zepto.js
//     (c) 2010, 2011 Thomas Fuchs
//     Zepto.js may be freely distributed under the MIT license.

(function($){
  var jsonpID = 0,
      isObject = $.isObject,
      key;

  // Empty function, used as default callback
  function empty() {}

  // ### $.ajaxJSONP
  //
  // Load JSON from a server in a different domain (JSONP)
  //
  // *Arguments:*
  //
  //     options — object that configure the request,
  //               see avaliable options below
  //
  // *Avaliable options:*
  //
  //     url     — url to which the request is sent
  //     success — callback that is executed if the request succeeds
  //     error   — callback that is executed if the server drops error
  //     context — in which context to execute the callbacks in
  //
  // *Example:*
  //
  //     $.ajaxJSONP({
  //        url:     'http://example.com/projects?callback=?',
  //        success: function (data) {
  //            projects.push(json);
  //        }
  //     });
  //
  $.ajaxJSONP = function(options){
    var callbackName = 'jsonp' + (++jsonpID),
      script = document.createElement('script'),
      context = options.context,
      abort = function(){
        $(script).remove();
        if (callbackName in window) window[callbackName] = empty;
      },
      xhr = { abort: abort }, abortTimeout;

    window[callbackName] = function(data){
      clearTimeout(abortTimeout);
      $(script).remove();
      delete window[callbackName];
      options.success.call(context, data);
    };

    script.src = options.url.replace(/=\?/, '=' + callbackName);
    $('head').append(script);

    if (options.timeout > 0) abortTimeout = setTimeout(function(){
        xhr.abort();
        options.error.call(context, xhr, 'timeout');
      }, options.timeout);

    return xhr;
  };

  // ### $.ajaxSettings
  //
  // AJAX settings
  //
  $.ajaxSettings = {
    // Default type of request
    type: 'GET',
    // Callback that is executed before request
    beforeSend: empty,
    // Callback that is executed if the request succeeds
    success: empty,
    // Callback that is executed the the server drops error
    error: empty,
    // Callback that is executed on request complete (both: error and success)
    complete: empty,
    // The context for the callbacks
    context: null,
    // Transport
    xhr: function () {
      return new window.XMLHttpRequest();
    },
    // MIME types mapping
    accepts: {
      script: 'text/javascript, application/javascript',
      json:   'application/json',
      xml:    'application/xml, text/xml',
      html:   'text/html',
      text:   'text/plain'
    },
    // Default timeout
    timeout: 0
  };

  // ### $.ajax
  //
  // Perform AJAX request
  //
  // *Arguments:*
  //
  //     options — object that configure the request,
  //               see avaliable options below
  //
  // *Avaliable options:*
  //
  //     type ('GET')          — type of request GET / POST
  //     url (window.location) — url to which the request is sent
  //     data                  — data to send to server,
  //                             can be string or object
  //     dataType ('json')     — what response type you accept from
  //                             the server:
  //                             'json', 'xml', 'html', or 'text'
  //     timeout (0)           — request timeout
  //     beforeSend            — callback that is executed before
  //                             request send
  //     complete              — callback that is executed on request
  //                             complete (both: error and success)
  //     success               — callback that is executed if
  //                             the request succeeds
  //     error                 — callback that is executed if
  //                             the server drops error
  //     context               — in which context to execute the
  //                             callbacks in
  //
  // *Example:*
  //
  //     $.ajax({
  //        type:       'POST',
  //        url:        '/projects',
  //        data:       { name: 'Zepto.js' },
  //        dataType:   'html',
  //        timeout:    100,
  //        context:    $('body'),
  //        success:    function (data) {
  //            this.append(data);
  //        },
  //        error:    function (xhr, type) {
  //            alert('Error!');
  //        }
  //     });
  //
  $.ajax = function(options){
    options = options || {};
    var settings = $.extend({}, options);
    for (key in $.ajaxSettings) if (!settings[key]) settings[key] = $.ajaxSettings[key];

    if (/=\?/.test(settings.url)) return $.ajaxJSONP(settings);

    if (!settings.url) settings.url = window.location.toString();
    if (settings.data && !settings.contentType) settings.contentType = 'application/x-www-form-urlencoded';
    if (isObject(settings.data)) settings.data = $.param(settings.data);

    if (settings.type.match(/get/i) && settings.data) {
      var queryString = settings.data;
      if (settings.url.match(/\?.*=/)) {
        queryString = '&' + queryString;
      } else if (queryString[0] != '?') {
        queryString = '?' + queryString;
      }
      settings.url += queryString;
    }

    var mime = settings.accepts[settings.dataType],
        xhr = $.ajaxSettings.xhr(), abortTimeout,
        context = settings.context;

    settings.headers = $.extend({'X-Requested-With': 'XMLHttpRequest'}, settings.headers || {});
    if (mime) settings.headers['Accept'] = mime;

    xhr.onreadystatechange = function(){
      if (xhr.readyState == 4) {
        clearTimeout(abortTimeout);
        var result, error = false;
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 0) {
          if (mime == 'application/json' && !(/^\s*$/.test(xhr.responseText))) {
            try { result = JSON.parse(xhr.responseText); }
            catch (e) { error = e; }
          }
          else result = xhr.responseText;
          if (error) settings.error.call(context, xhr, 'parsererror', error);
          else settings.success.call(context, result, 'success', xhr);
        } else {
          error = true;
          settings.error.call(context, xhr, 'error');
        }
        settings.complete.call(context, xhr, error ? 'error' : 'success');
      }
    };

    xhr.open(settings.type, settings.url, true);

    if (settings.contentType) settings.headers['Content-Type'] = settings.contentType;
    for (name in settings.headers) xhr.setRequestHeader(name, settings.headers[name]);

    if (settings.beforeSend.call(context, xhr, settings) === false) {
      xhr.abort();
      return false;
    }

    if (settings.timeout > 0) abortTimeout = setTimeout(function(){
        xhr.onreadystatechange = empty;
        xhr.abort();
        settings.error.call(context, xhr, 'timeout');
      }, settings.timeout);

    xhr.send(settings.data);
    return xhr;
  };

  // ### $.get
  //
  // Load data from the server using a GET request
  //
  // *Arguments:*
  //
  //     url     — url to which the request is sent
  //     success — callback that is executed if the request succeeds
  //
  // *Example:*
  //
  //     $.get(
  //        '/projects/42',
  //        function (data) {
  //            $('body').append(data);
  //        }
  //     );
  //
  $.get = function(url, success){ return $.ajax({ url: url, success: success }) };

  // ### $.post
  //
  // Load data from the server using POST request
  //
  // *Arguments:*
  //
  //     url        — url to which the request is sent
  //     [data]     — data to send to server, can be string or object
  //     [success]  — callback that is executed if the request succeeds
  //     [dataType] — type of expected response
  //                  'json', 'xml', 'html', or 'text'
  //
  // *Example:*
  //
  //     $.post(
  //        '/projects',
  //        { name: 'Zepto.js' },
  //        function (data) {
  //            $('body').append(data);
  //        },
  //        'html'
  //     );
  //
  $.post = function(url, data, success, dataType){
    if ($.isFunction(data)) dataType = dataType || success, success = data, data = null;
    return $.ajax({ type: 'POST', url: url, data: data, success: success, dataType: dataType });
  };

  // ### $.getJSON
  //
  // Load JSON from the server using GET request
  //
  // *Arguments:*
  //
  //     url     — url to which the request is sent
  //     success — callback that is executed if the request succeeds
  //
  // *Example:*
  //
  //     $.getJSON(
  //        '/projects/42',
  //        function (json) {
  //            projects.push(json);
  //        }
  //     );
  //
  $.getJSON = function(url, success){
    return $.ajax({ url: url, success: success, dataType: 'json' });
  };

  // ### $.fn.load
  //
  // Load data from the server into an element
  //
  // *Arguments:*
  //
  //     url     — url to which the request is sent
  //     [success] — callback that is executed if the request succeeds
  //
  // *Examples:*
  //
  //     $('#project_container').get(
  //        '/projects/42',
  //        function () {
  //            alert('Project was successfully loaded');
  //        }
  //     );
  //
  //     $('#project_comments').get(
  //        '/projects/42 #comments',
  //        function () {
  //            alert('Comments was successfully loaded');
  //        }
  //     );
  //
  $.fn.load = function(url, success){
    if (!this.length) return this;
    var self = this, parts = url.split(/\s/), selector;
    if (parts.length > 1) url = parts[0], selector = parts[1];
    $.get(url, function(response){
      self.html(selector ?
        $(document.createElement('div')).html(response).find(selector).html()
        : response);
      success && success.call(self);
    });
    return this;
  };

  var escape = encodeURIComponent;

  function serialize(params, obj, traditional, scope){
    var array = $.isArray(obj);
    $.each(obj, function(key, value) {
      if (scope) key = traditional ? scope : scope + '[' + (array ? '' : key) + ']';
      // handle data in serializeArray() format
      if (!scope && array) params.add(value.name, value.value);
      // recurse into nested objects
      else if (traditional ? $.isArray(value) : isObject(value))
        serialize(params, value, traditional, key);
      else params.add(key, value);
    });
  }

  // ### $.param
  //
  // Encode object as a string of URL-encoded key-value pairs
  //
  // *Arguments:*
  //
  //     obj — object to serialize
  //     [traditional] — perform shallow serialization
  //
  // *Example:*
  //
  //     $.param( { name: 'Zepto.js', version: '0.6' } );
  //
  $.param = function(obj, traditional){
    var params = [];
    params.add = function(k, v){ this.push(escape(k) + '=' + escape(v)) };
    serialize(params, obj, traditional);
    return params.join('&').replace('%20', '+');
  };
})(Zepto);
<commit_msg>Edited src/ajax.js via GitHub<commit_after>//     Zepto.js
//     (c) 2010, 2011 Thomas Fuchs
//     Zepto.js may be freely distributed under the MIT license.

(function($){
  var jsonpID = 0,
      isObject = $.isObject,
      key;

  // Empty function, used as default callback
  function empty() {}

  // ### $.ajaxJSONP
  //
  // Load JSON from a server in a different domain (JSONP)
  //
  // *Arguments:*
  //
  //     options — object that configure the request,
  //               see avaliable options below
  //
  // *Avaliable options:*
  //
  //     url     — url to which the request is sent
  //     success — callback that is executed if the request succeeds
  //     error   — callback that is executed if the server drops error
  //     context — in which context to execute the callbacks in
  //
  // *Example:*
  //
  //     $.ajaxJSONP({
  //        url:     'http://example.com/projects?callback=?',
  //        success: function (data) {
  //            projects.push(json);
  //        }
  //     });
  //
  $.ajaxJSONP = function(options){
    var callbackName = 'jsonp' + (++jsonpID),
      script = document.createElement('script'),
      context = options.context,
      abort = function(){
        $(script).remove();
        if (callbackName in window) window[callbackName] = empty;
      },
      xhr = { abort: abort }, abortTimeout;

    window[callbackName] = function(data){
      clearTimeout(abortTimeout);
      $(script).remove();
      delete window[callbackName];
      options.success.call(context, data);
    };

    script.src = options.url.replace(/=\?/, '=' + callbackName);
    $('head').append(script);

    if (options.timeout > 0) abortTimeout = setTimeout(function(){
        xhr.abort();
        options.error.call(context, xhr, 'timeout');
      }, options.timeout);

    return xhr;
  };

  // ### $.ajaxSettings
  //
  // AJAX settings
  //
  $.ajaxSettings = {
    // Default type of request
    type: 'GET',
    // Callback that is executed before request
    beforeSend: empty,
    // Callback that is executed if the request succeeds
    success: empty,
    // Callback that is executed the the server drops error
    error: empty,
    // Callback that is executed on request complete (both: error and success)
    complete: empty,
    // The context for the callbacks
    context: null,
    // Transport
    xhr: function () {
      return new window.XMLHttpRequest();
    },
    // MIME types mapping
    accepts: {
      script: 'text/javascript, application/javascript',
      json:   'application/json',
      xml:    'application/xml, text/xml',
      html:   'text/html',
      text:   'text/plain'
    },
    // Default timeout
    timeout: 0
  };

  // ### $.ajax
  //
  // Perform AJAX request
  //
  // *Arguments:*
  //
  //     options — object that configure the request,
  //               see avaliable options below
  //
  // *Avaliable options:*
  //
  //     type ('GET')          — type of request GET / POST
  //     url (window.location) — url to which the request is sent
  //     data                  — data to send to server,
  //                             can be string or object
  //     dataType ('json')     — what response type you accept from
  //                             the server:
  //                             'json', 'xml', 'html', or 'text'
  //     timeout (0)           — request timeout
  //     beforeSend            — callback that is executed before
  //                             request send
  //     complete              — callback that is executed on request
  //                             complete (both: error and success)
  //     success               — callback that is executed if
  //                             the request succeeds
  //     error                 — callback that is executed if
  //                             the server drops error
  //     context               — in which context to execute the
  //                             callbacks in
  //
  // *Example:*
  //
  //     $.ajax({
  //        type:       'POST',
  //        url:        '/projects',
  //        data:       { name: 'Zepto.js' },
  //        dataType:   'html',
  //        timeout:    100,
  //        context:    $('body'),
  //        success:    function (data) {
  //            this.append(data);
  //        },
  //        error:    function (xhr, type) {
  //            alert('Error!');
  //        }
  //     });
  //
  $.ajax = function(options){
    options = options || {};
    var settings = $.extend({}, options);
    for (key in $.ajaxSettings) if (!settings[key]) settings[key] = $.ajaxSettings[key];

    if (/=\?/.test(settings.url)) return $.ajaxJSONP(settings);

    if (!settings.url) settings.url = window.location.toString();
    if (settings.data && !settings.contentType) settings.contentType = 'application/x-www-form-urlencoded';
    if (isObject(settings.data)) settings.data = $.param(settings.data);

    if (settings.type.match(/get/i) && settings.data) {
      var queryString = settings.data;
      if (settings.url.match(/\?.*=/)) {
        queryString = '&' + queryString;
      } else if (queryString[0] != '?') {
        queryString = '?' + queryString;
      }
      settings.url += queryString;
    }

    var mime = settings.accepts[settings.dataType],
        xhr = $.ajaxSettings.xhr(), abortTimeout,
        context = settings.context;

    settings.headers = $.extend({'X-Requested-With': 'XMLHttpRequest'}, settings.headers || {});
    if (mime) settings.headers['Accept'] = mime;

    xhr.onreadystatechange = function(){
      if (xhr.readyState == 4) {
        clearTimeout(abortTimeout);
        var result, error = false;
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 0) {
          if (mime == 'application/json' && !(/^\s*$/.test(xhr.responseText))) {
            try { result = JSON.parse(xhr.responseText); }
            catch (e) { error = e; }
          }
          else result = xhr.responseText;
          if (error) settings.error.call(context, xhr, 'parsererror', error);
          else settings.success.call(context, result, 'success', xhr);
        } else {
          error = true;
          settings.error.call(context, xhr, 'error');
        }
        settings.complete.call(context, xhr, error ? 'error' : 'success');
      }
    };

    var async = settings.async != undefined ? settings.async : true;
    xhr.open(settings.type, settings.url, async);

    if (settings.contentType) settings.headers['Content-Type'] = settings.contentType;
    for (name in settings.headers) xhr.setRequestHeader(name, settings.headers[name]);

    if (settings.beforeSend.call(context, xhr, settings) === false) {
      xhr.abort();
      return false;
    }

    if (settings.timeout > 0) abortTimeout = setTimeout(function(){
        xhr.onreadystatechange = empty;
        xhr.abort();
        settings.error.call(context, xhr, 'timeout');
      }, settings.timeout);

    xhr.send(settings.data);
    return xhr;
  };

  // ### $.get
  //
  // Load data from the server using a GET request
  //
  // *Arguments:*
  //
  //     url     — url to which the request is sent
  //     success — callback that is executed if the request succeeds
  //
  // *Example:*
  //
  //     $.get(
  //        '/projects/42',
  //        function (data) {
  //            $('body').append(data);
  //        }
  //     );
  //
  $.get = function(url, success){ return $.ajax({ url: url, success: success }) };

  // ### $.post
  //
  // Load data from the server using POST request
  //
  // *Arguments:*
  //
  //     url        — url to which the request is sent
  //     [data]     — data to send to server, can be string or object
  //     [success]  — callback that is executed if the request succeeds
  //     [dataType] — type of expected response
  //                  'json', 'xml', 'html', or 'text'
  //
  // *Example:*
  //
  //     $.post(
  //        '/projects',
  //        { name: 'Zepto.js' },
  //        function (data) {
  //            $('body').append(data);
  //        },
  //        'html'
  //     );
  //
  $.post = function(url, data, success, dataType){
    if ($.isFunction(data)) dataType = dataType || success, success = data, data = null;
    return $.ajax({ type: 'POST', url: url, data: data, success: success, dataType: dataType });
  };

  // ### $.getJSON
  //
  // Load JSON from the server using GET request
  //
  // *Arguments:*
  //
  //     url     — url to which the request is sent
  //     success — callback that is executed if the request succeeds
  //
  // *Example:*
  //
  //     $.getJSON(
  //        '/projects/42',
  //        function (json) {
  //            projects.push(json);
  //        }
  //     );
  //
  $.getJSON = function(url, success){
    return $.ajax({ url: url, success: success, dataType: 'json' });
  };

  // ### $.fn.load
  //
  // Load data from the server into an element
  //
  // *Arguments:*
  //
  //     url     — url to which the request is sent
  //     [success] — callback that is executed if the request succeeds
  //
  // *Examples:*
  //
  //     $('#project_container').get(
  //        '/projects/42',
  //        function () {
  //            alert('Project was successfully loaded');
  //        }
  //     );
  //
  //     $('#project_comments').get(
  //        '/projects/42 #comments',
  //        function () {
  //            alert('Comments was successfully loaded');
  //        }
  //     );
  //
  $.fn.load = function(url, success){
    if (!this.length) return this;
    var self = this, parts = url.split(/\s/), selector;
    if (parts.length > 1) url = parts[0], selector = parts[1];
    $.get(url, function(response){
      self.html(selector ?
        $(document.createElement('div')).html(response).find(selector).html()
        : response);
      success && success.call(self);
    });
    return this;
  };

  var escape = encodeURIComponent;

  function serialize(params, obj, traditional, scope){
    var array = $.isArray(obj);
    $.each(obj, function(key, value) {
      if (scope) key = traditional ? scope : scope + '[' + (array ? '' : key) + ']';
      // handle data in serializeArray() format
      if (!scope && array) params.add(value.name, value.value);
      // recurse into nested objects
      else if (traditional ? $.isArray(value) : isObject(value))
        serialize(params, value, traditional, key);
      else params.add(key, value);
    });
  }

  // ### $.param
  //
  // Encode object as a string of URL-encoded key-value pairs
  //
  // *Arguments:*
  //
  //     obj — object to serialize
  //     [traditional] — perform shallow serialization
  //
  // *Example:*
  //
  //     $.param( { name: 'Zepto.js', version: '0.6' } );
  //
  $.param = function(obj, traditional){
    var params = [];
    params.add = function(k, v){ this.push(escape(k) + '=' + escape(v)) };
    serialize(params, obj, traditional);
    return params.join('&').replace('%20', '+');
  };
})(Zepto);
<|endoftext|>


<commit_before>'use strict';
var config = require("cheslie-config"),
  express = require('express'),
  app = express(),
  server = require('http').Server(app),
  io = require('socket.io', {
    extraHeaders: {
      Credentials: true
    }
  })(server),
  path = require('path'),
  Tournement = require('./tournement.js'),
  Player = require('./player.js'),
  api = require('./api.js')(io);

io.origins('*:*');

const PORT = process.env.PORT || config.tournament.port,
  IS_DEV = process.env.NODE_ENV === 'development';

if (IS_DEV) {
  webpackDevSetup(app);
} else {
  app.use(express.static(path.join(__dirname, '..', 'dist')));
}

var players = [],
  globalTourney;
io.on('connect', socket => {
  if (!globalTourney) globalTourney = new Tournement([], api);
  socket.on('enter', playerName => {
    players.push(new Player(socket, playerName));
    api.broadcast('players', players);
    console.log('New player entered lobby, %s', playerName);
  })

  socket.on('add-player', (clientPlayer) => {
    if (!globalTourney) return;
    var player = Player.fromClient(clientPlayer, players);
    globalTourney.addPlayer(player)
    api.broadcast('players', players);
  })

  socket.on('remove-player', (clientPlayer) => {
    if (!globalTourney) return;
    if (globalTourney.started) return;
    var player = Player.fromClient(clientPlayer, players);
    globalTourney.removePlayer(player)
    api.broadcast('players', players);
  })

  socket.on('update', () => {
    console.log('client update');
    socket.emit('players', players);
    if (globalTourney) globalTourney.updateClient();
  })

  socket.on('reset-tourney', () => {
    if (globalTourney) globalTourney.stop();
    players.map(player => { player.reset() })
    globalTourney = new Tournement([], api);
    api.broadcast('players', players);
  })

  socket.on('start-tourney', (tourney) => {
    if (!globalTourney) return;
    if (!globalTourney.isReadyToStart()) return;

    globalTourney.start();
  })

  socket.on('disconnect', () => {
    players = players.filter((player) => { return player.id !== socket.id });
    api.broadcast('players', players);
  });
});

server.listen(PORT, function (error) {
  if (error) {
    console.log(error);
  } else {
    console.log('Server listening on port 2208');
  }
});

function webpackDevSetup(app) {
  var webpack = require('webpack'),
    webpackDevMiddleware = require('webpack-dev-middleware'),
    webpackHotMiddleware = require('webpack-hot-middleware'),
    webpackconfig = require('../webpack.config.js'),
    compiler = webpack(webpackconfig);
  app.use(express.static(path.join(__dirname, '..', 'app')));
  app.use(webpackDevMiddleware(compiler, {
    publicPath: webpackconfig.output.publicPath
  }));
  app.use(webpackHotMiddleware(compiler));
}<commit_msg>Maybe express will work<commit_after>'use strict';
var config = require("cheslie-config"),
  express = require('express'),
  app = express(),
  server = require('http').Server(app),
  io = require('socket.io')(server),
  path = require('path'),
  Tournement = require('./tournement.js'),
  Player = require('./player.js'),
  api = require('./api.js')(io);

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

const PORT = process.env.PORT || config.tournament.port,
  IS_DEV = process.env.NODE_ENV === 'development';

if (IS_DEV) {
  webpackDevSetup(app);
} else {
  app.use(express.static(path.join(__dirname, '..', 'dist')));
}

var players = [],
  globalTourney;
io.on('connect', socket => {
  if (!globalTourney) globalTourney = new Tournement([], api);
  socket.on('enter', playerName => {
    players.push(new Player(socket, playerName));
    api.broadcast('players', players);
    console.log('New player entered lobby, %s', playerName);
  })

  socket.on('add-player', (clientPlayer) => {
    if (!globalTourney) return;
    var player = Player.fromClient(clientPlayer, players);
    globalTourney.addPlayer(player)
    api.broadcast('players', players);
  })

  socket.on('remove-player', (clientPlayer) => {
    if (!globalTourney) return;
    if (globalTourney.started) return;
    var player = Player.fromClient(clientPlayer, players);
    globalTourney.removePlayer(player)
    api.broadcast('players', players);
  })

  socket.on('update', () => {
    console.log('client update');
    socket.emit('players', players);
    if (globalTourney) globalTourney.updateClient();
  })

  socket.on('reset-tourney', () => {
    if (globalTourney) globalTourney.stop();
    players.map(player => { player.reset() })
    globalTourney = new Tournement([], api);
    api.broadcast('players', players);
  })

  socket.on('start-tourney', (tourney) => {
    if (!globalTourney) return;
    if (!globalTourney.isReadyToStart()) return;

    globalTourney.start();
  })

  socket.on('disconnect', () => {
    players = players.filter((player) => { return player.id !== socket.id });
    api.broadcast('players', players);
  });
});

server.listen(PORT, function (error) {
  if (error) {
    console.log(error);
  } else {
    console.log('Server listening on port 2208');
  }
});

function webpackDevSetup(app) {
  var webpack = require('webpack'),
    webpackDevMiddleware = require('webpack-dev-middleware'),
    webpackHotMiddleware = require('webpack-hot-middleware'),
    webpackconfig = require('../webpack.config.js'),
    compiler = webpack(webpackconfig);
  app.use(express.static(path.join(__dirname, '..', 'app')));
  app.use(webpackDevMiddleware(compiler, {
    publicPath: webpackconfig.output.publicPath
  }));
  app.use(webpackHotMiddleware(compiler));
}<|endoftext|>


<commit_before>import { NodeComponent, without } from 'substance'

class RefListComponent extends NodeComponent {

  didMount() {
    super.didMount()
    this.context.labelGenerator.on('labels:generated', this._onLabelsChanged, this)

    this.handleActions({
      'removeRef': this._removeRef
    })
  }

  dispose() {
    super.dispose()
    this.context.labelGenerator.off(this)
  }

  render($$) {
    const labelGenerator = this.context.labelGenerator
    const node = this.props.node

    let el = $$('div').addClass('sc-ref-list')
    // NOTE: We don't yet expose RefList.label to the editor
    let title = node.find('title')
    if (title) {
      el.append(
        $$('div').addClass('se-title').append(
          $$(this.getComponent('text-property-editor'), {
            path: title.getTextPath(),
            disabled: this.props.disabled
          })
        )
      )
    }
    let refs = node.findAll('ref')
    let entries = refs.map((ref) => {
      return {
        // NOTE: refs without a position, i.e. which are not referenced
        // should end up at the end of the list
        pos: labelGenerator.getPosition('bibr', ref.id) || Number.MAX_VALUE,
        ref
      }
    })
    entries.sort((a,b) => {
      return a.pos - b.pos
    })
    entries.forEach((entry) => {
      const ref = entry.ref
      let RefComponent = this.getComponent('ref')
      el.append(
        $$(RefComponent, { node: ref }).ref(ref.id)
      )
    })

    el.append(
      $$('div').append(
        $$('button').addClass('sg-big-button')
          .append('Add Reference')
          .on('click', this._addRef)
      )
    )
    return el
  }

  _onLabelsChanged(refType) {
    if (refType === 'bibr') {
      this.rerender()
    }
  }

  /*
    Insert new Reference

    <ref>
      <string-citation>Please enter publication name</string-citation>
    </ref>
  */
  _addRef() {
    const editorSession = this.context.editorSession
    editorSession.transaction((doc) => {
      let refList = doc.find('ref-list')
      let ref = doc.createElement('ref')
      let elementCitation = doc.createElement('element-citation').attr('publication-type', 'journal')
      elementCitation.append(
        doc.createElement('person-group').attr('person-group-type', 'author'),
        doc.createElement('year').attr('iso-8601-date', ''),
        doc.createElement('article-title'),
        doc.createElement('source'),
        doc.createElement('volume'),
        doc.createElement('issue'),
        doc.createElement('fpage'),
        doc.createElement('lpage'),
        doc.createElement('pub-id').attr('pub-id-type', 'doi'),
        doc.createElement('pub-id').attr('pub-id-type', 'pubmed')
      )
      ref.append(elementCitation)
      refList.append(ref)
    })
    this.rerender()
  }

  _removeRef(refId) {
    let editorSession = this.context.editorSession
    editorSession.transaction(doc => {
      let xrefIndex = doc.getIndex('xrefs')
      let xrefs = xrefIndex.get(refId)
      xrefs.forEach((xrefId) => {
        let xref = doc.get(xrefId)
        let idrefs = xref.attr('rid').split(' ')
        idrefs = without(idrefs, refId)
        xref.setAttribute('rid', idrefs.join(' '))
      })
      let fnGroup = doc.find('ref-list')
      let ref = fnGroup.find(`ref#${refId}`)
      fnGroup.removeChild(ref)
    })
    this.rerender()
  }

}

export default RefListComponent
<commit_msg>Fix typo.<commit_after>import { NodeComponent, without } from 'substance'

class RefListComponent extends NodeComponent {

  didMount() {
    super.didMount()
    this.context.labelGenerator.on('labels:generated', this._onLabelsChanged, this)

    this.handleActions({
      'removeRef': this._removeRef
    })
  }

  dispose() {
    super.dispose()
    this.context.labelGenerator.off(this)
  }

  render($$) {
    const labelGenerator = this.context.labelGenerator
    const node = this.props.node

    let el = $$('div').addClass('sc-ref-list')
    // NOTE: We don't yet expose RefList.label to the editor
    let title = node.find('title')
    if (title) {
      el.append(
        $$('div').addClass('se-title').append(
          $$(this.getComponent('text-property-editor'), {
            path: title.getTextPath(),
            disabled: this.props.disabled
          })
        )
      )
    }
    let refs = node.findAll('ref')
    let entries = refs.map((ref) => {
      return {
        // NOTE: refs without a position, i.e. which are not referenced
        // should end up at the end of the list
        pos: labelGenerator.getPosition('bibr', ref.id) || Number.MAX_VALUE,
        ref
      }
    })
    entries.sort((a,b) => {
      return a.pos - b.pos
    })
    entries.forEach((entry) => {
      const ref = entry.ref
      let RefComponent = this.getComponent('ref')
      el.append(
        $$(RefComponent, { node: ref }).ref(ref.id)
      )
    })

    el.append(
      $$('div').append(
        $$('button').addClass('sg-big-button')
          .append('Add Reference')
          .on('click', this._addRef)
      )
    )
    return el
  }

  _onLabelsChanged(refType) {
    if (refType === 'bibr') {
      this.rerender()
    }
  }

  /*
    Insert new Reference

    <ref>
      <string-citation>Please enter publication name</string-citation>
    </ref>
  */
  _addRef() {
    const editorSession = this.context.editorSession
    editorSession.transaction((doc) => {
      let refList = doc.find('ref-list')
      let ref = doc.createElement('ref')
      let elementCitation = doc.createElement('element-citation').attr('publication-type', 'journal')
      elementCitation.append(
        doc.createElement('person-group').attr('person-group-type', 'author'),
        doc.createElement('year').attr('iso-8601-date', ''),
        doc.createElement('article-title'),
        doc.createElement('source'),
        doc.createElement('volume'),
        doc.createElement('issue'),
        doc.createElement('fpage'),
        doc.createElement('lpage'),
        doc.createElement('pub-id').attr('pub-id-type', 'doi'),
        doc.createElement('pub-id').attr('pub-id-type', 'pmid')
      )
      ref.append(elementCitation)
      refList.append(ref)
    })
    this.rerender()
  }

  _removeRef(refId) {
    let editorSession = this.context.editorSession
    editorSession.transaction(doc => {
      let xrefIndex = doc.getIndex('xrefs')
      let xrefs = xrefIndex.get(refId)
      xrefs.forEach((xrefId) => {
        let xref = doc.get(xrefId)
        let idrefs = xref.attr('rid').split(' ')
        idrefs = without(idrefs, refId)
        xref.setAttribute('rid', idrefs.join(' '))
      })
      let fnGroup = doc.find('ref-list')
      let ref = fnGroup.find(`ref#${refId}`)
      fnGroup.removeChild(ref)
    })
    this.rerender()
  }

}

export default RefListComponent
<|endoftext|>


<commit_before>const throng = require('throng')
const WORKERS = process.env.WEB_CONCURRENCY || 1
require('dotenv').config()

const express = require('express')
const logger = require('winston')
// const { firebase } = require('./firebase')
// const util = require('./util')
const initializeApp = require('./initialize')
// const processUserGraph = require('./actions/process-user-graph')
// const webUtil = require('./webUtil')

//=========================================================
//  SETUP
//---------------------------------------------------------
const app = express()

app.set('host', process.env.HOST || 'localhost')
app.set('port', process.env.PORT || 3001)

//=========================================================
//  ROUTER
//---------------------------------------------------------
// const router = new express.Router()
//
// router.get('/graph/:id', webUtil.handle(function* gen(req) {
//   return processUserGraph({ data: { userId: req.params.id }})
// }))
//
// app.use(router)

//=========================================================
//  START SERVER
//---------------------------------------------------------
const start = (id) => {
  const isMaster = id === 1 // The first worker is the master
  initializeApp(isMaster).then(() => {
    app.listen(app.get('port'), app.get('host'), error => {
      if (error) {
        logger.error(error)
      } else {
        logger.info(`Server ${id} listening @ ${app.get('host')}:${app.get('port')}`)
      }
    })
  })
}

// Cluster the server
throng({
  start,
  workers: WORKERS,
  lifetime: Infinity
})
<commit_msg>Update server<commit_after>const throng = require('throng')
const WORKERS = process.env.WEB_CONCURRENCY || 1
require('dotenv').config()

const express = require('express')
const logger = require('winston')
const initializeApp = require('./initialize')
const webUtil = require('./webUtil')

//=========================================================
//  SETUP
//---------------------------------------------------------
const app = express()

app.set('host', process.env.HOST || 'localhost')
app.set('port', process.env.PORT || 3001)

//=========================================================
//  ROUTER
//---------------------------------------------------------
const router = new express.Router()

router.get('/hello', webUtil.handle(function* gen() {
  return 'dog!'
}))

app.use(router)

//=========================================================
//  START SERVER
//---------------------------------------------------------
const start = (id) => {
  const isMaster = id === 1 // The first worker is the master
  initializeApp(isMaster).then(() => {
    app.listen(app.get('port'), app.get('host'), error => {
      if (error) {
        logger.error(error)
      } else {
        logger.info(`Server ${id} listening @ ${app.get('host')}:${app.get('port')}`)
      }
    })
  })
}

// Cluster the server
throng({
  start,
  workers: WORKERS,
  lifetime: Infinity
})
<|endoftext|>


<commit_before>'use strict';
var React = require('react');
var url = require('url');
var _ = require('underscore');
var graph = require('./graph');
var globals = require('./globals');
var dbxref = require('./dbxref');
var search = require('./search');
var StatusLabel = require('./statuslabel').StatusLabel;
var Citation = require('./publication').Citation;
var audit = require('./audit');

var Graph = graph.Graph;
var JsonGraph = graph.JsonGraph;
var AuditIndicators = audit.AuditIndicators;
var AuditDetail = audit.AuditDetail;
var AuditMixin = audit.AuditMixin;

var DbxrefList = dbxref.DbxrefList;

var Panel = function (props) {
    // XXX not all panels have the same markup
    var context;
    if (props['@id']) {
        context = props;
        props = {context: context};
    }
    var PanelView = globals.panel_views.lookup(props.context);
    return <PanelView {...props} />;
};

var Pipeline = module.exports.Pipeline = React.createClass({
    mixins: [AuditMixin],

    getInitialState: function() {
        return {
            infoNodeId: '' // ID of node whose info panel is open
        };
    },

    assembleGraph: function() {
        var jsonGraph;
        var analysis_steps = this.props.context.analysis_steps;

        // Only produce a graph if there's at least one analysis step
        if (analysis_steps && analysis_steps.length) {
            // Make an object with all step UUIDs in the pipeline
            var allSteps = {};
            analysis_steps.forEach(function(step) {
                allSteps[step.uuid] = step;
            });

            // Create an empty graph architecture
            jsonGraph = new JsonGraph(this.props.context.accession);

            // Add files and their steps as nodes to the graph
            analysis_steps.forEach(function(step) {
                var stepId = step['@id'];

                // Make an array of step types
                var stepTypesList = step.analysis_step_types.map(function(type) {
                    return type;
                });

                // Assemble a single analysis step node.
                jsonGraph.addNode(stepId, step.name,
                    {cssClass: 'pipeline-node-analysis-step' + (this.state.infoNodeId === stepId ? ' active' : ''), type: 'step', shape: 'rect', cornerRadius: 4, ref: step});

                // If the node has parents, render the edges to those parents
                if (step.parents && step.parents.length) {
                    step.parents.forEach(function(parent) {
                        if (parent.uuid in allSteps) {
                            jsonGraph.addEdge(parent['@id'], stepId);
                        }
                    });
                }
            }, this);

            // If any analysis step parents haven't been seen yet,
            // add them to the graph too
            analysis_steps.forEach(function(step) {
                if (step.parents && step.parents.length) {
                    step.parents.forEach(function(parent) {
                        if (parent.uuid in allSteps) {
                            var stepId = parent['@id'];
                            if (!jsonGraph.getNode(stepId)) {
                                // Make an array of step types
                                var stepTypesList = parent.analysis_step_types.map(function(type) {
                                    return type;
                                });

                                // Assemble a single analysis step node.
                                jsonGraph.addNode(stepId, stepTypesList.join(', '),
                                    {cssClass: 'pipeline-node-analysis-step' + (this.state.infoNodeId === stepId ? ' active' : ''), type: 'step', shape: 'rect', cornerRadius: 4, ref: parent});
                            }
                        }
                    }, this);
                }
            }, this);

        }
        return jsonGraph;
    },

    detailNodes: function(jsonGraph, infoNodeId) {
        var meta;

        // Find data matching selected node, if any
        if (infoNodeId) {
            var node = jsonGraph.getNode(infoNodeId);
            if (node) {
                meta = globals.graph_detail.lookup(node)(node);
            }
        }

        return meta;
    },

    handleNodeClick: function(nodeId) {
        this.setState({infoNodeId: this.state.infoNodeId !== nodeId ? nodeId : ''});
    },

    render: function() {
        var context = this.props.context;
        var itemClass = globals.itemClass(context, 'view-item');

        var documents = {};
        if (context.documents) {
            context.documents.forEach(function(doc, i) {
                documents[doc['@id']] = Panel({context: doc, key: i + 1});
            });
        }

        // Build node graph of the files and analysis steps with this experiment
        this.jsonGraph = this.assembleGraph();

        // Find the selected step, if any
        var selectedStep;
        if (this.state.infoNodeId) {
            var selectedNode = this.jsonGraph.getNode(this.state.infoNodeId);
            if (selectedNode) {
                selectedStep = selectedNode.metadata.ref;
            }
        }

        return (

{context.title}

                                <StatusLabel title="Status" status={context.status} />

                            <AuditIndicators audits={context.audit} id="biosample-audit" />

                <AuditDetail context={context} id="biosample-audit" />

                        {context.accession ?

Accession

{context.accession}

                        : null}

Title

{context.source_url ? {context.title} : context.title}

                        {context.version ?

Version

{context.version}

                        : null}

                        {context.assay_term_name ?

Assay

{context.assay_term_name}

                        : null}

Lab

{context.lab.title}

                        {context.award.pi && context.award.pi.lab ?

Award PI

{context.award.pi.lab.title}

                        : null}

                        {context.description ?

Description

{context.description}

                        : null}

                {this.jsonGraph ?

Pipeline schematic

                        <Graph graph={this.jsonGraph} nodeClickHandler={this.handleNodeClick}>

                                {selectedStep ?

                                        <AnalysisStep step={selectedStep} />

                                : null}

                        </Graph>

                : null}
                {context.documents && context.documents.length ?

Documents

                            {context.documents.map(function(doc) {
                                return <Panel context={doc} />;
                            })}

                : null}

        );
    }
});
globals.content_views.register(Pipeline, 'pipeline');

var AnalysisStep = module.exports.AnalysisStep = React.createClass({
    render: function() {
        var step = this.props.step;
        var node = this.props.node;
        var typesList = step.analysis_step_types.join(", ");

        return (

Name

{step.title}

Step type

{step.analysis_step_types.join(', ')}

Step name

{step.name}

                    {step.input_file_types && step.input_file_types.length ?

Input

{step.input_file_types.join(', ')}

                    : null}

                    {step.output_file_types && step.output_file_types.length ?

Output

{step.output_file_types.map(function(type, i) {
                                return (

                                        {i > 0 ? {','}
 : null}
                                        {type}

                                );
                            })}

                    : null}

                    {node && node.metadata.pipeline ?

Pipeline

{node.metadata.pipeline.title}

                    : null}

                    {step.qa_stats_generated && step.qa_stats_generated.length ?

QA statistics

{step.qa_stats_generated.map(function(stat, i) {
                                return (

                                        {i > 0 ? {','}
 : null}
                                        {stat}

                                );
                            })}

                    : null}

                    {step.software_versions && step.software_versions.length ?

Software

                                {step.software_versions.map(function(version, i) {
                                    var versionNum = version.version === 'unknown' ? 'version unknown' : version.version;
                                    return (

                                            {version.software.name}
                                            {version.version ?
                                                {versionNum}
                                            : null}

                                    );
                                })}

                    : null}

                    {step.documents && step.documents.length ?

Documents

                                {step.documents.map(function(document, i) {
                                    var docName = document.attachment ? document.attachment.download : document['@id'];
                                    return ({i > 0 ? ', ' : null}{docName});
                                })}

                    : null}

                    {step.aliases.length ?

Aliases

{step.aliases.join(', ')}

                    : null}

        );
    }
});

// Display the metadata of the selected analysis step in the graph
var StepDetailView = module.exports.StepDetailView = function(node) {
    // The node is for a step. It can be called with analysis_step_run (for file graphs) or analysis_step (for pipeline graphs) nodes.
    // This code detects which is the case, and adjusts accordingly.
    var selectedStep = node.metadata.ref;
    var meta;

    if (selectedStep) {
        return <AnalysisStep step={selectedStep} node={node} />;
    } else {
        return (
Missing step_run derivation information for {node.metadata.fileAccession}
);
    }
};

globals.graph_detail.register(StepDetailView, 'step');

var Listing = React.createClass({
    mixins: [search.PickerActionsMixin, AuditMixin],
    render: function() {
        var result = this.props.context;
        var publishedBy = [];
        var swTitle = [];

        // Collect up an array of published-by and software titles for all steps in this pipeline
        if (result.analysis_steps && result.analysis_steps.length) {
            result.analysis_steps.forEach(function(step) {
                step.software_versions.forEach(function(version) {
                    swTitle.push(version.software.title);
                    if (version.software.references && version.software.references.length) {
                        version.software.references.forEach(function(reference) {
                            publishedBy.push.apply(publishedBy, reference.published_by); // add published_by array to publishedBy array
                        });
                    }
                });
            });
        }
        publishedBy = _.uniq(publishedBy);
        swTitle = _.uniq(swTitle);

        return (

                    {this.renderActions()}

Pipeline

{' ' + result['accession']}

                        {result.status ?
{' ' + result.status}
 : ''}
                        <AuditIndicators audits={result.audit} id={result['@id']} search />

                        {result['title']}

                        {result.assay_term_name ?

Assay: {result.assay_term_name}

                        : null}

                        {swTitle.length ?

Software: {swTitle.join(', ')}

                        : null}

                <AuditDetail context={result} id={this.props.context['@id']} forcedEditLink />

        );
    }
});
globals.listing_views.register(Listing, 'pipeline');

var PipelineTable = module.exports.PipelineTable = React.createClass({
    render: function() {
        var pipelines;

        // If there's a limit on entries to display and the array is greater than that
        // limit, then clone the array with just that specified number of elements
        if (this.props.limit && (this.props.limit < this.props.items.length)) {
            // Limit the pipelines list by cloning first {limit} elements
            pipelines = this.props.items.slice(0, this.props.limit);
        } else {
            // No limiting; just reference the original array
            pipelines = this.props.items;
        }

        // Get the software version numbers for all matching software
        var softwareId = url.parse(this.props.href).pathname;
        var swVers = [];
        pipelines.forEach(function(pipeline, i) {
            return pipeline.analysis_steps.some(function(analysis_step) {
                // Get the software_version object for any with a software @id matching softwareId, and save to array
                var matchedSwVers = _(analysis_step.software_versions).find(function(software_version) {
                    return software_version.software['@id'] === softwareId;
                });
                if (matchedSwVers) {
                    swVers[i] = matchedSwVers;
                }
                return matchedSwVers;
            });
        });

        return (

                            Pipeline
                            Assay
                            Version
                            Download checksum

                    {pipelines.map(function (pipeline, i) {
                        // Ensure this can work with search result columns too
                        return (

                                {pipeline.accession}
                                {pipeline.assay_term_name}
                                {swVers[i].version}
                                {swVers[i].download_checksum}

                        );
                    })}

                                {this.props.limit && (this.props.limit < this.props.total) ?

                                        {'Displaying '}{this.props.limit}{' pipelines out of '}{this.props.total}{' total related pipelines'}

                                : ''}

        );
    }
});
<commit_msg>Show more pipeline node info in graph<commit_after>'use strict';
var React = require('react');
var url = require('url');
var _ = require('underscore');
var graph = require('./graph');
var globals = require('./globals');
var dbxref = require('./dbxref');
var search = require('./search');
var StatusLabel = require('./statuslabel').StatusLabel;
var Citation = require('./publication').Citation;
var audit = require('./audit');

var Graph = graph.Graph;
var JsonGraph = graph.JsonGraph;
var AuditIndicators = audit.AuditIndicators;
var AuditDetail = audit.AuditDetail;
var AuditMixin = audit.AuditMixin;

var DbxrefList = dbxref.DbxrefList;

var Panel = function (props) {
    // XXX not all panels have the same markup
    var context;
    if (props['@id']) {
        context = props;
        props = {context: context};
    }
    var PanelView = globals.panel_views.lookup(props.context);
    return <PanelView {...props} />;
};

var Pipeline = module.exports.Pipeline = React.createClass({
    mixins: [AuditMixin],

    getInitialState: function() {
        return {
            infoNodeId: '' // ID of node whose info panel is open
        };
    },

    assembleGraph: function() {
        var jsonGraph;
        var analysis_steps = this.props.context.analysis_steps;

        // Only produce a graph if there's at least one analysis step
        if (analysis_steps && analysis_steps.length) {
            // Make an object with all step UUIDs in the pipeline
            var allSteps = {};
            analysis_steps.forEach(function(step) {
                allSteps[step.uuid] = step;
            });

            // Create an empty graph architecture
            jsonGraph = new JsonGraph(this.props.context.accession);

            // Add files and their steps as nodes to the graph
            analysis_steps.forEach(function(step) {
                var stepId = step['@id'];
                var swVersionList = [];
                var label;

                // Make an array of step types
                var stepTypesList = step.analysis_step_types.map(function(type) {
                    return type;
                });

                // Collect software version titles
                if (step.software_versions && step.software_versions.length) {
                    swVersionList = step.software_versions.map(function(version) {
                        return version.software.title;
                    });
                }

                // Build the node label; both step types and sw version titles if available
                if (swVersionList.length) {
                    label = [step.analysis_step_types.join(', '), swVersionList.join(', ')];
                } else {
                    label = step.analysis_step_types.join(', ');
                }

                // Assemble a single analysis step node.
                jsonGraph.addNode(stepId, label,
                    {cssClass: 'pipeline-node-analysis-step' + (this.state.infoNodeId === stepId ? ' active' : ''), type: 'step', shape: 'rect', cornerRadius: 4, ref: step});

                // If the node has parents, render the edges to those parents
                if (step.parents && step.parents.length) {
                    step.parents.forEach(function(parent) {
                        if (parent.uuid in allSteps) {
                            jsonGraph.addEdge(parent['@id'], stepId);
                        }
                    });
                }
            }, this);

            // If any analysis step parents haven't been seen yet,
            // add them to the graph too
            analysis_steps.forEach(function(step) {
                if (step.parents && step.parents.length) {
                    step.parents.forEach(function(parent) {
                        if (parent.uuid in allSteps) {
                            var stepId = parent['@id'];
                            var swVersionList = [];
                            var label;

                            if (!jsonGraph.getNode(stepId)) {
                                // Collect software version titles
                                if (parent.software_versions && parent.software_versions.length) {
                                    swVersionList = parent.software_versions.map(function(version) {
                                        return version.software.title;
                                    });
                                }

                                // Build the node label; both step types and sw version titles if available
                                if (swVersionList.length) {
                                    label = [parent.analysis_step_types.join(', '), swVersionList.join(', ')];
                                } else {
                                    label = parent.analysis_step_types.join(', ');
                                }

                                // Assemble a single analysis step node.
                                jsonGraph.addNode(stepId, label,
                                    {cssClass: 'pipeline-node-analysis-step' + (this.state.infoNodeId === stepId ? ' active' : ''), type: 'step', shape: 'rect', cornerRadius: 4, ref: parent});
                            }
                        }
                    }, this);
                }
            }, this);

        }
        return jsonGraph;
    },

    detailNodes: function(jsonGraph, infoNodeId) {
        var meta;

        // Find data matching selected node, if any
        if (infoNodeId) {
            var node = jsonGraph.getNode(infoNodeId);
            if (node) {
                meta = globals.graph_detail.lookup(node)(node);
            }
        }

        return meta;
    },

    handleNodeClick: function(nodeId) {
        this.setState({infoNodeId: this.state.infoNodeId !== nodeId ? nodeId : ''});
    },

    render: function() {
        var context = this.props.context;
        var itemClass = globals.itemClass(context, 'view-item');

        var documents = {};
        if (context.documents) {
            context.documents.forEach(function(doc, i) {
                documents[doc['@id']] = Panel({context: doc, key: i + 1});
            });
        }

        // Build node graph of the files and analysis steps with this experiment
        this.jsonGraph = this.assembleGraph();

        // Find the selected step, if any
        var selectedStep;
        if (this.state.infoNodeId) {
            var selectedNode = this.jsonGraph.getNode(this.state.infoNodeId);
            if (selectedNode) {
                selectedStep = selectedNode.metadata.ref;
            }
        }

        return (

{context.title}

                                <StatusLabel title="Status" status={context.status} />

                            <AuditIndicators audits={context.audit} id="biosample-audit" />

                <AuditDetail context={context} id="biosample-audit" />

                        {context.accession ?

Accession

{context.accession}

                        : null}

Title

{context.source_url ? {context.title} : context.title}

                        {context.version ?

Version

{context.version}

                        : null}

                        {context.assay_term_name ?

Assay

{context.assay_term_name}

                        : null}

Lab

{context.lab.title}

                        {context.award.pi && context.award.pi.lab ?

Award PI

{context.award.pi.lab.title}

                        : null}

                        {context.description ?

Description

{context.description}

                        : null}

                {this.jsonGraph ?

Pipeline schematic

                        <Graph graph={this.jsonGraph} nodeClickHandler={this.handleNodeClick}>

                                {selectedStep ?

                                        <AnalysisStep step={selectedStep} />

                                : null}

                        </Graph>

                : null}
                {context.documents && context.documents.length ?

Documents

                            {context.documents.map(function(doc) {
                                return <Panel context={doc} />;
                            })}

                : null}

        );
    }
});
globals.content_views.register(Pipeline, 'pipeline');

var AnalysisStep = module.exports.AnalysisStep = React.createClass({
    render: function() {
        var step = this.props.step;
        var node = this.props.node;
        var typesList = step.analysis_step_types.join(", ");

        return (

Name

{step.title}

Step type

{step.analysis_step_types.join(', ')}

Step name

{step.name}

                    {step.input_file_types && step.input_file_types.length ?

Input

{step.input_file_types.join(', ')}

                    : null}

                    {step.output_file_types && step.output_file_types.length ?

Output

{step.output_file_types.map(function(type, i) {
                                return (

                                        {i > 0 ? {','}
 : null}
                                        {type}

                                );
                            })}

                    : null}

                    {node && node.metadata.pipeline ?

Pipeline

{node.metadata.pipeline.title}

                    : null}

                    {step.qa_stats_generated && step.qa_stats_generated.length ?

QA statistics

{step.qa_stats_generated.map(function(stat, i) {
                                return (

                                        {i > 0 ? {','}
 : null}
                                        {stat}

                                );
                            })}

                    : null}

                    {step.software_versions && step.software_versions.length ?

Software

                                {step.software_versions.map(function(version, i) {
                                    var versionNum = version.version === 'unknown' ? 'version unknown' : version.version;
                                    return (

                                            {version.software.name}
                                            {version.version ?
                                                {versionNum}
                                            : null}

                                    );
                                })}

                    : null}

                    {step.documents && step.documents.length ?

Documents

                                {step.documents.map(function(document, i) {
                                    var docName = document.attachment ? document.attachment.download : document['@id'];
                                    return ({i > 0 ? ', ' : null}{docName});
                                })}

                    : null}

                    {step.aliases.length ?

Aliases

{step.aliases.join(', ')}

                    : null}

        );
    }
});

// Display the metadata of the selected analysis step in the graph
var StepDetailView = module.exports.StepDetailView = function(node) {
    // The node is for a step. It can be called with analysis_step_run (for file graphs) or analysis_step (for pipeline graphs) nodes.
    // This code detects which is the case, and adjusts accordingly.
    var selectedStep = node.metadata.ref;
    var meta;

    if (selectedStep) {
        return <AnalysisStep step={selectedStep} node={node} />;
    } else {
        return (
Missing step_run derivation information for {node.metadata.fileAccession}
);
    }
};

globals.graph_detail.register(StepDetailView, 'step');

var Listing = React.createClass({
    mixins: [search.PickerActionsMixin, AuditMixin],
    render: function() {
        var result = this.props.context;
        var publishedBy = [];
        var swTitle = [];

        // Collect up an array of published-by and software titles for all steps in this pipeline
        if (result.analysis_steps && result.analysis_steps.length) {
            result.analysis_steps.forEach(function(step) {
                step.software_versions.forEach(function(version) {
                    swTitle.push(version.software.title);
                    if (version.software.references && version.software.references.length) {
                        version.software.references.forEach(function(reference) {
                            publishedBy.push.apply(publishedBy, reference.published_by); // add published_by array to publishedBy array
                        });
                    }
                });
            });
        }
        publishedBy = _.uniq(publishedBy);
        swTitle = _.uniq(swTitle);

        return (

                    {this.renderActions()}

Pipeline

{' ' + result['accession']}

                        {result.status ?
{' ' + result.status}
 : ''}
                        <AuditIndicators audits={result.audit} id={result['@id']} search />

                        {result['title']}

                        {result.assay_term_name ?

Assay: {result.assay_term_name}

                        : null}

                        {swTitle.length ?

Software: {swTitle.join(', ')}

                        : null}

                <AuditDetail context={result} id={this.props.context['@id']} forcedEditLink />

        );
    }
});
globals.listing_views.register(Listing, 'pipeline');

var PipelineTable = module.exports.PipelineTable = React.createClass({
    render: function() {
        var pipelines;

        // If there's a limit on entries to display and the array is greater than that
        // limit, then clone the array with just that specified number of elements
        if (this.props.limit && (this.props.limit < this.props.items.length)) {
            // Limit the pipelines list by cloning first {limit} elements
            pipelines = this.props.items.slice(0, this.props.limit);
        } else {
            // No limiting; just reference the original array
            pipelines = this.props.items;
        }

        // Get the software version numbers for all matching software
        var softwareId = url.parse(this.props.href).pathname;
        var swVers = [];
        pipelines.forEach(function(pipeline, i) {
            return pipeline.analysis_steps.some(function(analysis_step) {
                // Get the software_version object for any with a software @id matching softwareId, and save to array
                var matchedSwVers = _(analysis_step.software_versions).find(function(software_version) {
                    return software_version.software['@id'] === softwareId;
                });
                if (matchedSwVers) {
                    swVers[i] = matchedSwVers;
                }
                return matchedSwVers;
            });
        });

        return (

                            Pipeline
                            Assay
                            Version
                            Download checksum

                    {pipelines.map(function (pipeline, i) {
                        // Ensure this can work with search result columns too
                        return (

                                {pipeline.accession}
                                {pipeline.assay_term_name}
                                {swVers[i].version}
                                {swVers[i].download_checksum}

                        );
                    })}

                                {this.props.limit && (this.props.limit < this.props.total) ?

                                        {'Displaying '}{this.props.limit}{' pipelines out of '}{this.props.total}{' total related pipelines'}

                                : ''}

        );
    }
});
<|endoftext|>


<commit_before>(function($){
  var jsonpID = 0;

  function empty() {}

  $.ajaxJSONP = function(options){
    var jsonpString;
    jsonpString = 'jsonp' + ++jsonpID;
    window[jsonpString] = function(data){
      options.success(data);
      delete window.jsonpString;
    };
    var script = document.createElement('script');
    $(script).attr({ src: options.url.replace(/=\?/, '=' + jsonpString) });
    $('head').append(script);
  };

  $.ajax = function(options){
    // { type, url, data, success, dataType, contentType }
    options = options || {};

    if (options.url && /=\?/.test(options.url))
      return $.ajaxJSONP(options);

    var data = options.data,
        callback = options.success || empty,
        errback = options.error || empty,
        mime = mimeTypes[options.dataType],
        type = options.type || "GET",
        content = options.contentType || (type === "POST" ? "application/x-www-form-urlencoded" : ""),
        xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function(){
      if (xhr.readyState == 4) {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 0) {
          if (mime == 'application/json') {
            var result, error = false;
            try {
              result = JSON.parse(xhr.responseText);
            } catch (e) {
              error = e;
            }
            if (error) errback(xhr, 'parsererror', error);
            else callback(result, 'success', xhr);
          } else callback(xhr.responseText, 'success', xhr);
        } else {
          errback(xhr, 'error');
        }
      }
    };

    xhr.open(type, options.url || window.location, true);
    if (mime) xhr.setRequestHeader('Accept', mime);
    if (data instanceof Object) data = $.param(data);
    if (content) xhr.setRequestHeader('Content-Type', content);
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.send(data);
  };

  var mimeTypes = $.ajax.mimeTypes = {
    json: 'application/json',
    xml:  'application/xml',
    html: 'text/html',
    text: 'text/plain'
  };

  $.get = function(url, success){ $.ajax({ url: url, success: success }) };
  $.post = function(url, data, success, dataType){
    if (data instanceof Function) dataType = dataType || success, success = data, data = null;
    $.ajax({ type: 'POST', url: url, data: data, success: success, dataType: dataType });
  };
  $.getJSON = function(url, success){ $.ajax({ url: url, success: success, dataType: 'json' }) };

  $.fn.load = function(url, success){
    if (!this.length) return this;
    var self = this, parts = url.split(/\s/), selector;
    if (parts.length > 1) url = parts[0], selector = parts[1];
    $.get(url, function(response){
      self.html(selector ?
        $(document.createElement('div')).html(response).find(selector).html()
        : response);
      success && success();
    });
    return this;
  };

  $.param = function(obj, v){
    var s = [],
        rec = '',
        add = function(key, value){
          if(v) s[s.length] = encodeURIComponent(v + "[" + key +"]") + '=' + encodeURIComponent(value);
          else s[s.length] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
        };
    for(var i in obj){
      if(obj[i] instanceof Array || obj[i] instanceof Object)
        rec += (s.length + rec.length > 0 ? '&' : '') + $.param(obj[i], (v ? v + "[" + (obj[i] instanceof Object ? i : '') + "]" : i));
      else
        add(obj instanceof Array ? '' : i, obj[i]);
    };
    return s.join("&").replace(/%20/g, "+") + rec;
  };
})(Zepto);
<commit_msg>Small bug fix introduced when modifying $.param to better resemble jQuerys implementation<commit_after>(function($){
  var jsonpID = 0;

  function empty() {}

  $.ajaxJSONP = function(options){
    var jsonpString;
    jsonpString = 'jsonp' + ++jsonpID;
    window[jsonpString] = function(data){
      options.success(data);
      delete window.jsonpString;
    };
    var script = document.createElement('script');
    $(script).attr({ src: options.url.replace(/=\?/, '=' + jsonpString) });
    $('head').append(script);
  };

  $.ajax = function(options){
    // { type, url, data, success, dataType, contentType }
    options = options || {};

    if (options.url && /=\?/.test(options.url))
      return $.ajaxJSONP(options);

    var data = options.data,
        callback = options.success || empty,
        errback = options.error || empty,
        mime = mimeTypes[options.dataType],
        type = options.type || "GET",
        content = options.contentType || (type === "POST" ? "application/x-www-form-urlencoded" : ""),
        xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function(){
      if (xhr.readyState == 4) {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 0) {
          if (mime == 'application/json') {
            var result, error = false;
            try {
              result = JSON.parse(xhr.responseText);
            } catch (e) {
              error = e;
            }
            if (error) errback(xhr, 'parsererror', error);
            else callback(result, 'success', xhr);
          } else callback(xhr.responseText, 'success', xhr);
        } else {
          errback(xhr, 'error');
        }
      }
    };

    xhr.open(type, options.url || window.location, true);
    if (mime) xhr.setRequestHeader('Accept', mime);
    if (data instanceof Object) data = $.param(data);
    if (content) xhr.setRequestHeader('Content-Type', content);
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.send(data);
  };

  var mimeTypes = $.ajax.mimeTypes = {
    json: 'application/json',
    xml:  'application/xml',
    html: 'text/html',
    text: 'text/plain'
  };

  $.get = function(url, success){ $.ajax({ url: url, success: success }) };
  $.post = function(url, data, success, dataType){
    if (data instanceof Function) dataType = dataType || success, success = data, data = null;
    $.ajax({ type: 'POST', url: url, data: data, success: success, dataType: dataType });
  };
  $.getJSON = function(url, success){ $.ajax({ url: url, success: success, dataType: 'json' }) };

  $.fn.load = function(url, success){
    if (!this.length) return this;
    var self = this, parts = url.split(/\s/), selector;
    if (parts.length > 1) url = parts[0], selector = parts[1];
    $.get(url, function(response){
      self.html(selector ?
        $(document.createElement('div')).html(response).find(selector).html()
        : response);
      success && success();
    });
    return this;
  };

  $.param = function(obj, v){
    var s = [],
        rec = '',
        add = function(key, value){
          if(v) s[s.length] = encodeURIComponent(v + "[" + key +"]") + '=' + encodeURIComponent(value);
          else s[s.length] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
        };
    for(var i in obj){
      if(obj[i] instanceof Array || obj[i] instanceof Object)
        rec += (s.length + rec.length > 0 ? '&' : '') + $.param(obj[i], (v ? v + "[" + i + "]" : i));
      else
        add(obj instanceof Array ? '' : i, obj[i]);
    };
    return s.join("&").replace(/%20/g, "+") + rec;
  };
})(Zepto);
<|endoftext|>


<commit_before>const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const Sequelize = require('sequelize');
const loginCheck = require('./controllers/loginCheck.js');
const UserResponseController = require('./controllers/userResponseController');
const changePW = require('./controllers/changePassword.js');
const quizTakenController = require('./controllers/quizTakenController.js');
const runJob = require('./cronJob.js');
const Users = require('./Users/UserModel.js');
// Constants
const port = process.env.PORT || 3000;
const app = express();

app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, './../')));
runJob();
// The root route serves the main html page
app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, '../src/', 'main.html'));
});

// Post requests to the login route validates email and password
// DB should return:
// 1) If Admin flag
// 2) 3 questions
// 3) Error if doesn't match
// 4) First login flag
app.post('/login',
  loginCheck.validUser,
  // loginCheck.isAdmin,
  // loginCheck.firstLogin,
  loginCheck.getQuestions,
  quizTakenController.checkQuizWasTaken,
  quizTakenController.checkQuizAvailability,
(req, res) => {
  res.send(JSON.stringify(req.results));
});

// Post requests to change password changes user's pw in the db
app.post('/changePassword', changePW.changePasswordInDB, function (req, res) {
  res.statusCode = 200;
  res.send(JSON.stringify('Succesfully updated password'));
});

// Get requests to results will return user or admin data
app.get('/results', function (req, res) {

});

app.post('/userResponse', UserResponseController.addResults , function(req, res) {
  res.send('Successful post request!');
});

// For all other requests, serve main html page
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, '../src/', 'main.html'));
});

app.listen(port);

app.destroy = () => {
  process.exit();
};
console.log('Running on http://localhost:' + port);

module.exports = app;

// OLD BOILER PLATE FOR WEBPACK IMPROVEMENTS

// const webpack = require('webpack');
// const WebpackDevServer = require('webpack-dev-server');
// const config = require('../webpack.config');

// app.get('/app.js', (req, res) => {
//   if (process.env.PRODUCTION) {
//     res.sendFile(__dirname + '/build/build.js');
//   } else {
//     res.redirect('//localhost:9090/build/build.js');
//   }
// });

// Serve aggregate stylesheet depending on environment
// NEED TO UPDATE WHEN WE HAVE STYLES
// app.get('/style.css', (req, res) => {
//   if (process.env.PRODUCTION) {
//     res.sendFile(__dirname + '/client/style.css');
//   } else {
//     res.redirect('//localhost:9090/client/style.css');
//   }
// });

// new WebpackDevServer(webpack(config), {
//   publicPath: config.output.publicPath,
//   hot: true,
//   noInfo: true,
//   historyApiFallback: true,
// }).listen(9090, 'localhost', (err, result) => {
//   if (err) {
//     console.log(err);
//   }
//   console.log('webpack i think');
// });
<commit_msg>Update server.js<commit_after>const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const Sequelize = require('sequelize');
const loginCheck = require('./controllers/loginCheck.js');
const UserResponseController = require('./controllers/userResponseController');
const changePW = require('./controllers/changePassword.js');
const quizTakenController = require('./controllers/quizTakenController.js');
const runJob = require('./cronJob.js');
// Constants
const port = process.env.PORT || 3000;
const app = express();

app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, './../')));
runJob();
// The root route serves the main html page
app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, '../src/', 'main.html'));
});

// Post requests to the login route validates email and password
// DB should return:
// 1) If Admin flag
// 2) 3 questions
// 3) Error if doesn't match
// 4) First login flag
app.post('/login',
  loginCheck.validUser,
  // loginCheck.isAdmin,
  // loginCheck.firstLogin,
  loginCheck.getQuestions,
  quizTakenController.checkQuizWasTaken,
  quizTakenController.checkQuizAvailability,
(req, res) => {
  res.send(JSON.stringify(req.results));
});

// Post requests to change password changes user's pw in the db
app.post('/changePassword', changePW.changePasswordInDB, function (req, res) {
  res.statusCode = 200;
  res.send(JSON.stringify('Succesfully updated password'));
});

// Get requests to results will return user or admin data
app.get('/results', function (req, res) {

});

app.post('/userResponse', UserResponseController.addResults , function(req, res) {
  res.send('Successful post request!');
});

// For all other requests, serve main html page
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, '../src/', 'main.html'));
});

app.listen(port);

app.destroy = () => {
  process.exit();
};
console.log('Running on http://localhost:' + port);

module.exports = app;

// OLD BOILER PLATE FOR WEBPACK IMPROVEMENTS

// const webpack = require('webpack');
// const WebpackDevServer = require('webpack-dev-server');
// const config = require('../webpack.config');

// app.get('/app.js', (req, res) => {
//   if (process.env.PRODUCTION) {
//     res.sendFile(__dirname + '/build/build.js');
//   } else {
//     res.redirect('//localhost:9090/build/build.js');
//   }
// });

// Serve aggregate stylesheet depending on environment
// NEED TO UPDATE WHEN WE HAVE STYLES
// app.get('/style.css', (req, res) => {
//   if (process.env.PRODUCTION) {
//     res.sendFile(__dirname + '/client/style.css');
//   } else {
//     res.redirect('//localhost:9090/client/style.css');
//   }
// });

// new WebpackDevServer(webpack(config), {
//   publicPath: config.output.publicPath,
//   hot: true,
//   noInfo: true,
//   historyApiFallback: true,
// }).listen(9090, 'localhost', (err, result) => {
//   if (err) {
//     console.log(err);
//   }
//   console.log('webpack i think');
// });
<|endoftext|>


<commit_before>/*eslint no-console: 0*/
/*global __DEVELOPMENT__ webpackIsomorphicTools */
import 'babel-polyfill'
import Compression from 'compression'
import Express from 'express'
import path from 'path'

import React from 'react'
import ReactDOMServer from 'react-dom/server'
import createLocation from 'history/lib/createLocation'
import { RoutingContext, match } from 'react-router'
import createMemoryHistory from 'history/lib/createMemoryHistory'
import Promise from 'bluebird'
import httpProxy from 'http-proxy'

import configureStore from '../src/store/configureStore'
import crateRoutes from '../src/routes/index'

import { Provider } from 'react-redux'
import config from './config'

import {  NotFoundError } from '../src/lib/custom-error'
import _ from 'lodash'

const server = new Express()
const targetUrl = 'http://' + config.apiHost + ':' + config.apiPort
// create a proxy server to serve the API requests
const proxy = httpProxy.createProxyServer({
  target: targetUrl
})

server.set('views', path.join(__dirname, 'views'))
server.set('view engine', 'ejs')
server.use(Compression())
server.use(Express.static(path.join(__dirname, '../static')))
server.use(function (req, res, next) {
  res.header('Access-Control-Allow-Origin', 'http://www.twreporter.org/')
  res.header('Access-Control-Allow-Headers', 'X-Requested-With')
  next()
})

// mock apis
//server.get('/questions', (req, res)=> {
//  let { questions } = require('./mock_api');
//  res.send(questions);
//});
//
server.get('/robots.txt', (req, res) => {
  res.format({
    'text/plain': function () {
      res.status(200).render('robots')
    }
  })
})
// proxy to the API server
server.use('/api', (req, res) => {
  proxy.web(req, res)
})

// added the error handling to avoid https://github.com/nodejitsu/node-http-proxy/issues/527
proxy.on('error', (error, req, res) => {
  let json
  if (error.code !== 'ECONNRESET') {
    console.error('proxy error', error)
  }
  if (!res.headersSent) {
    res.writeHead(500, { 'content-type': 'application/json' })
  }
  json = { error: 'proxy_error', reason: error.message }
  res.end(JSON.stringify(json))
})

server.get('*', (req, res) => {
  if (__DEVELOPMENT__) {
    // Do not cache webpack stats: the script file would change since
    // hot module replacement is enabled in the development env
    webpackIsomorphicTools.refresh()
  }
  let history = createMemoryHistory()
  let store = configureStore()

  let routes = crateRoutes(history)

  let location = createLocation(req.url)

  match({ routes, location }, (error, redirectLocation, renderProps) => {
    if (redirectLocation) {
      res.redirect(301, redirectLocation.pathname + redirectLocation.search)
    } else if (error) {
      res.status(500).render('500')
    } else if (renderProps == null) {
      res.status(404).render('404')
    } else {

      let [ getCurrentUrl, unsubscribe ] = subscribeUrl()
      let reqUrl = location.pathname + location.search
      store.dispatch({
        type: 'DETECT_DEVICE',
        headers: _.get(req, [ 'headers', 'user-agent' ])
      })

      const getReduxPromise = function () {
        let { query, params } = renderProps
        let comp = renderProps.components[renderProps.components.length - 1].WrappedComponent
        let promise = comp.fetchData ?
          comp.fetchData({ query, params, store, history }) :
          Promise.resolve()

        return promise
      }

      getReduxPromise().then(()=> {
        let fatalError = store.getState().fatalError
        if (fatalError) {
          throw fatalError
        }
        let reduxState = escape(JSON.stringify(store.getState()))
        let html = ReactDOMServer.renderToString(
          <Provider store={store} >
            { <RoutingContext {...renderProps} /> }
          </Provider>
        )
        let assets = webpackIsomorphicTools.assets()
        {/* styles (will be present only in production with webpack extract text plugin) */}
        let styles = ''
        {
          Object.keys(assets.styles).map((style, key) => {
            styles += ReactDOMServer.renderToString(<link href={assets.styles[style]} key={key} media="screen, projection" rel="stylesheet" type="text/css" charSet="UTF-8"/>)
          }
        )}

        if ( getCurrentUrl() === reqUrl ) {
          res.render('index', { html, reduxState, styles, javascript: assets.javascript.main })
        } else {
          res.redirect(302, getCurrentUrl())
        }
        unsubscribe()
      }).catch((err) => {
        console.log(err.stack)
        if (err instanceof NotFoundError) {
          res.status(404)
          res.render('404')
          return
        }
        res.status(500)
        let errStack = err.stack.split('\n')
        res.render('500', { error: errStack })
      })
    }
  })

  function subscribeUrl() {
    let currentUrl = location.pathname + location.search
    let unsubscribe = history.listen((newLoc) => {
      if (newLoc.action === 'PUSH') {
        currentUrl = newLoc.pathname + newLoc.search
      }
    })
    return [
      ()=> currentUrl,
      unsubscribe
    ]
  }
})

if (config.port) {
  server.listen(config.port, (err) => {
    if (err) {
      console.error(err)
    }
    console.info('----\n==> ✅  %s is running, talking to API server on %s.', config.app.title, config.apiPort)
    console.info('==> 💻  Open http://%s:%s in a browser to view the app.', config.host, config.port)
  })
} else {
  console.error('==>     ERROR: No PORT environment variable has been specified')
}

module.exports = server
<commit_msg>use RouterContext instead of RoutingContext AND use createMemoryHistory which is in react-router instead of history<commit_after>/*eslint no-console: 0*/
/*global __DEVELOPMENT__ webpackIsomorphicTools */
import 'babel-polyfill'
import Compression from 'compression'
import Express from 'express'
import path from 'path'

import React from 'react'
import ReactDOMServer from 'react-dom/server'
import createLocation from 'history/lib/createLocation'
import { RouterContext, match, createMemoryHistory } from 'react-router'
import Promise from 'bluebird'
import httpProxy from 'http-proxy'

import configureStore from '../src/store/configureStore'
import crateRoutes from '../src/routes/index'

import { Provider } from 'react-redux'
import config from './config'

import {  NotFoundError } from '../src/lib/custom-error'
import _ from 'lodash'

const server = new Express()
const targetUrl = 'http://' + config.apiHost + ':' + config.apiPort
// create a proxy server to serve the API requests
const proxy = httpProxy.createProxyServer({
  target: targetUrl
})

server.set('views', path.join(__dirname, 'views'))
server.set('view engine', 'ejs')
server.use(Compression())
server.use(Express.static(path.join(__dirname, '../static')))
server.use(function (req, res, next) {
  res.header('Access-Control-Allow-Origin', 'http://www.twreporter.org/')
  res.header('Access-Control-Allow-Headers', 'X-Requested-With')
  next()
})

// mock apis
//server.get('/questions', (req, res)=> {
//  let { questions } = require('./mock_api');
//  res.send(questions);
//});
//
server.get('/robots.txt', (req, res) => {
  res.format({
    'text/plain': function () {
      res.status(200).render('robots')
    }
  })
})
// proxy to the API server
server.use('/api', (req, res) => {
  proxy.web(req, res)
})

// added the error handling to avoid https://github.com/nodejitsu/node-http-proxy/issues/527
proxy.on('error', (error, req, res) => {
  let json
  if (error.code !== 'ECONNRESET') {
    console.error('proxy error', error)
  }
  if (!res.headersSent) {
    res.writeHead(500, { 'content-type': 'application/json' })
  }
  json = { error: 'proxy_error', reason: error.message }
  res.end(JSON.stringify(json))
})

server.get('*', (req, res) => {
  if (__DEVELOPMENT__) {
    // Do not cache webpack stats: the script file would change since
    // hot module replacement is enabled in the development env
    webpackIsomorphicTools.refresh()
  }
  let history = createMemoryHistory()
  let store = configureStore()

  let routes = crateRoutes(history)

  let location = createLocation(req.url)

  match({ routes, location }, (error, redirectLocation, renderProps) => {
    if (redirectLocation) {
      res.redirect(301, redirectLocation.pathname + redirectLocation.search)
    } else if (error) {
      res.status(500).render('500')
    } else if (renderProps == null) {
      res.status(404).render('404')
    } else {

      let [ getCurrentUrl, unsubscribe ] = subscribeUrl()
      let reqUrl = location.pathname + location.search
      store.dispatch({
        type: 'DETECT_DEVICE',
        headers: _.get(req, [ 'headers', 'user-agent' ])
      })

      const getReduxPromise = function () {
        let { query, params } = renderProps
        let comp = renderProps.components[renderProps.components.length - 1].WrappedComponent
        let promise = comp.fetchData ?
          comp.fetchData({ query, params, store, history }) :
          Promise.resolve()

        return promise
      }

      getReduxPromise().then(()=> {
        let fatalError = store.getState().fatalError
        if (fatalError) {
          throw fatalError
        }
        let reduxState = escape(JSON.stringify(store.getState()))
        let html = ReactDOMServer.renderToString(
          <Provider store={store} >
            { <RouterContext {...renderProps} /> }
          </Provider>
        )
        let assets = webpackIsomorphicTools.assets()
        {/* styles (will be present only in production with webpack extract text plugin) */}
        let styles = ''
        {
          Object.keys(assets.styles).map((style, key) => {
            styles += ReactDOMServer.renderToString(<link href={assets.styles[style]} key={key} media="screen, projection" rel="stylesheet" type="text/css" charSet="UTF-8"/>)
          }
        )}

        if ( getCurrentUrl() === reqUrl ) {
          res.render('index', { html, reduxState, styles, javascript: assets.javascript.main })
        } else {
          res.redirect(302, getCurrentUrl())
        }
        unsubscribe()
      }).catch((err) => {
        console.log(err.stack)
        if (err instanceof NotFoundError) {
          res.status(404)
          res.render('404')
          return
        }
        res.status(500)
        let errStack = err.stack.split('\n')
        res.render('500', { error: errStack })
      })
    }
  })

  function subscribeUrl() {
    let currentUrl = location.pathname + location.search
    let unsubscribe = history.listen((newLoc) => {
      if (newLoc.action === 'PUSH') {
        currentUrl = newLoc.pathname + newLoc.search
      }
    })
    return [
      ()=> currentUrl,
      unsubscribe
    ]
  }
})

if (config.port) {
  server.listen(config.port, (err) => {
    if (err) {
      console.error(err)
    }
    console.info('----\n==> ✅  %s is running, talking to API server on %s.', config.app.title, config.apiPort)
    console.info('==> 💻  Open http://%s:%s in a browser to view the app.', config.host, config.port)
  })
} else {
  console.error('==>     ERROR: No PORT environment variable has been specified')
}

module.exports = server
<|endoftext|>