<commit_before>var eventQueue = [];
var svg;
var element;
var drawingArea;
var width;
var height;
var volume = 0.6;
var ULTIMATE_DREAM_KILLER = false;  // https://github.com/debugger22/github-audio/pull/19
var orgRepoFilterNames = [];

var scale_factor = 6,
    note_overlap = 2,
    note_timeout = 300,
    current_notes = 0,
    max_life = 20000;

var svg_background_color_online = '#0288D1',
    svg_background_color_offline = '#E91E63'
    svg_text_color = '#FFFFFF',
    newuser_box_color = 'rgb(41, 128, 185)',
    push_color = 'rgb(155, 89, 182)',
    issue_color = 'rgb(46, 204, 113)',
    pull_request_color = 'rgb(46, 204, 113)',
    comment_color = 'rgb(46, 204, 113)'
    edit_color = '#fff',
    total_sounds = 51;

    var celesta = [],
        clav = [],
        swells = [],
        all_loaded = false;

var socket = io();
socket.on('github', function (data) {
  $('.online-users-count').html(data.connected_users);
  data.data.forEach(function(event){
    if(!isEventInQueue(event)){
      // Filter out events only specified by the user
      if(orgRepoFilterNames != []){
        // Don't consider pushes to github.io repos when org filter is on
        if(new RegExp(orgRepoFilterNames.join("|")).test(event.repo_name)
           && event.repo_name.indexOf('github.io') == -1){
          eventQueue.push(event);
        }
      }else{
        eventQueue.push(event);
      }
    }
  });
  // Don't let the eventQueue grow more than 1000
  if (eventQueue.length > 1000) eventQueue = eventQueue.slice(0, 1000);
});

socket.on('connect', function(){
    if(svg != null){
      $('svg').css('background-color', svg_background_color_online);
      $('header').css('background-color', svg_background_color_online);
      $('.offline-text').css('visibility', 'hidden');
      $('.events-remaining-text').css('visibility', 'hidden');
      $('.events-remaining-value').css('visibility', 'hidden');
    }
});

socket.on('disconnect', function(){
    if(svg != null){
      $('svg').css('background-color', svg_background_color_offline);
      $('header').css('background-color', svg_background_color_offline);
      $('.offline-text').css('visibility', 'visible');
      $('.events-remaining-text').css('visibility', 'visible');
      $('.events-remaining-value').css('visibility', 'visible');

    }
});

socket.on('error', function(){
    if(svg != null){
      $('svg').css('background-color', svg_background_color_offline);
      $('header').css('background-color', svg_background_color_offline);
      $('.offline-text').css('visibility', 'visible');
      $('.events-remaining-text').css('visibility', 'visible');
      $('.events-remaining-value').css('visibility', 'visible');
    }
});

/**
* This function checks whether an event is already in the queue
*/
function isEventInQueue(event){
  for(var i=0; i<eventQueue.length; i++){
    if(eventQueue[i].id == event.id)
      return true;
  }
  return false;
}

/**
 * This function adds a filter for events that we don't want to hear.
 *
 * To extend this function, simply add return true for events that should be filtered.
 */
function shouldEventBeIgnored(event){
  // This adds an easter egg to only play closed PRs
  if (!!ULTIMATE_DREAM_KILLER)
    return (event.type !== "PullRequestEvent" || event.action !== "closed");

  return false;
}

$(function(){
  element = document.documentElement;
  drawingArea = document.getElementsByTagName('#area')[0];
  width = window.innerWidth || element.clientWidth || drawingArea.clientWidth;
  height = (window.innerHeight  - $('header').height())|| (element.clientHeight - $('header').height()) || (drawingArea.clientHeight - $('header').height());
  $('svg').css('background-color', svg_background_color_online);
  $('header').css('background-color', svg_background_color_online);
  $('svg text').css('color', svg_text_color);
  $('#volumeSlider').slider({
    'max': 100,
    'min': 0,
    'value': volume*100,
    'slide' : function(event, ui){
      volume = ui.value/100.0;
      Howler.volume(volume);
    },
    'change' : function(event, ui){
      volume = ui.value/100.0;
      Howler.volume(volume);
    }
  });

  // Main drawing area
  svg = d3.select("#area").append("svg");
  svg.attr({width: width, height: height});
  svg.style('background-color', svg_background_color_online);

  // For window resizes
  var update_window = function() {
      width = window.innerWidth || element.clientWidth || drawingArea.clientWidth;
      height = (window.innerHeight  - $('header').height())|| (element.clientHeight - $('header').height()) || (drawingArea.clientHeight - $('header').height());
      svg.attr("width", width).attr("height", height);
  }
  window.onresize = update_window;
  update_window();

  var loaded_sounds = 0;
  var sound_load = function(r) {
      loaded_sounds += 1;
      if (loaded_sounds == total_sounds) {
          all_loaded = true;
          setTimeout(playFromQueueExchange1, Math.floor(Math.random() * 1000));
          // Starting the second exchange makes music a bad experience
          // setTimeout(playFromQueueExchange2, Math.floor(Math.random() * 2000));
      }
  }

  // Load sounds
  for (var i = 1; i <= 24; i++) {
      if (i > 9) {
          fn = 'c0' + i;
      } else {
          fn = 'c00' + i;
      }
      celesta.push(new Howl({
          src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/celesta/' + fn + '.ogg',
                  'https://d1fz9d31zqor6x.cloudfront.net/sounds/celesta/' + fn + '.mp3'],
          volume : 0.7,
          onload : sound_load(),
          buffer: true,
      }))
      clav.push(new Howl({
          src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/clav/' + fn + '.ogg',
                  'https://d1fz9d31zqor6x.cloudfront.net/sounds/clav/' + fn + '.mp3'],
          volume : 0.4,
          onload : sound_load(),
          buffer: true,
      }))
  }

  for (var i = 1; i <= 3; i++) {
      swells.push(new Howl({
          src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/swells/swell' + i + '.ogg',
                  'https://d1fz9d31zqor6x.cloudfront.net/sounds/swells/swell' + i + '.mp3'],
          volume : 1,
          onload : sound_load(),
          buffer: true,
      }));
  }

  Howler.volume(volume);

  // Make header and footer visible
  $('body').css('visibility', 'visible');

  $('#org-repo-filter-name').on('input', function() {
    orgRepoFilterNames = $('#org-repo-filter-name').val().split(' ');
    eventQueue = [];
  });

});

/**
* Randomly selects a swell sound and plays it
*/
function playRandomSwell() {
    var index = Math.round(Math.random() * (swells.length - 1));
    swells[index].play();
}

/**
* Plays a sound(celesta and clav) based on passed parameters
*/
function playSound(size, type) {
    var max_pitch = 100.0;
    var log_used = 1.0715307808111486871978099;
    var pitch = 100 - Math.min(max_pitch, Math.log(size + log_used) / Math.log(log_used));
    var index = Math.floor(pitch / 100.0 * Object.keys(celesta).length);
    var fuzz = Math.floor(Math.random() * 4) - 2;
    index += fuzz;
    index = Math.min(Object.keys(celesta).length - 1, index);
    index = Math.max(1, index);
    if (current_notes < note_overlap) {
        current_notes++;
        if (type == 'IssuesEvent' || type == 'IssueCommentEvent') {
            clav[index].play();
        } else if(type == 'PushEvent') {
            celesta[index].play();
        }else{
          playRandomSwell();
        }
        setTimeout(function() {
            current_notes--;
        }, note_timeout);
    }
}

// Following are the n numbers of event consumers
// consuming n events each per second with a random delay between them

function playFromQueueExchange1(){
  var event = eventQueue.shift();
  if(event != null && event.message != null && !shouldEventBeIgnored(event) && svg != null){
    playSound(event.message.length*1.1, event.type);
    if(!document.hidden)
      drawEvent(event, svg);
  }
  setTimeout(playFromQueueExchange1, Math.floor(Math.random() * 1000) + 500);
  $('.events-remaining-value').html(eventQueue.length);
}

function playFromQueueExchange2(){
  var event = eventQueue.shift();
  if(event != null && event.message != null && !shouldEventBeIgnored(event) && svg != null){
    playSound(event.message.length, event.type);
    if(!document.hidden)
      drawEvent(event, svg);
  }
  setTimeout(playFromQueueExchange2, Math.floor(Math.random() * 800) + 500);
  $('.events-remaining-value').html(eventQueue.length);
}

// This method capitalizes the string in place
String.prototype.capitalize=function(all){
    if(all){
      return this.split(' ').map(function(e){
        return e.capitalize().join(' ');
      });
    }else{
         return this.charAt(0).toUpperCase() + this.slice(1);
    }
}

function drawEvent(data, svg_area) {
    var starting_opacity = 1;
    var opacity = 1 / (100 / data.message.length);
    if (opacity > 0.5) {
        opacity = 0.5;
    }
    var size = data.message.length;
    var label_text;
    var ring_radius = 80;
    var ring_anim_duration = 3000;
    svg_text_color = '#FFFFFF';
    switch(data.type){
      case "PushEvent":
        label_text = data.user.capitalize() + " pushed to " + data.repo_name;
        edit_color = '#B2DFDB';
      break;
      case "PullRequestEvent":
        label_text = data.user.capitalize() + " " +
          data.action + " " + " a PR for " + data.repo_name;
          edit_color = '#C6FF00';
          ring_anim_duration = 10000;
          ring_radius = 600;
      break;
      case "IssuesEvent":
        label_text = data.user.capitalize() + " " +
          data.action + " an issue in " + data.repo_name;
          edit_color = '#FFEB3B';
      break;
      case "IssueCommentEvent":
        label_text = data.user.capitalize() + " commented in " + data.repo_name;
        edit_color = '#FF5722';
      break;
    }
    var csize = size;
    var no_label = false;
    var type = data.type;

    var circle_id = 'd' + ((Math.random() * 100000) | 0);
    var abs_size = Math.abs(size);
    size = Math.max(Math.sqrt(abs_size) * scale_factor, 3);

    Math.seedrandom(data.message)
    var x = Math.random() * (width - size) + size;
    var y = Math.random() * (height - size) + size;

    var circle_group = svg_area.append('g')
        .attr('transform', 'translate(' + x + ', ' + y + ')')
        .attr('fill', edit_color)
        .style('opacity', starting_opacity)

    var ring = circle_group.append('circle');
    ring.attr({r: size, stroke: 'none'});
    ring.transition()
        .attr('r', size + ring_radius)
        .style('opacity', 0)
        .ease(Math.sqrt)
        .duration(ring_anim_duration)
        .remove();

    var circle_container = circle_group.append('a');
    circle_container.attr('xlink:href', data.url);
    circle_container.attr('target', '_blank');
    circle_container.attr('fill', svg_text_color);

    var circle = circle_container.append('circle');
    circle.classed(type, true);
    circle.attr('r', size)
      .attr('fill', edit_color)
      .transition()
      .duration(max_life)
      .style('opacity', 0)
      .remove();

    circle_container.on('mouseover', function() {
      circle_container.append('text')
          .text(label_text)
          .classed('label', true)
          .attr('text-anchor', 'middle')
          .attr('font-size', '0.8em')
          .transition()
          .delay(1000)
          .style('opacity', 0)
          .duration(2000)
          .each(function() { no_label = true; })
          .remove();
    });

    var text = circle_container.append('text')
        .text(label_text)
        .classed('article-label', true)
        .attr('text-anchor', 'middle')
        .attr('font-size', '0.8em')
        .transition()
        .delay(2000)
        .style('opacity', 0)
        .duration(5000)
        .each(function() { no_label = true; })
        .remove();

  // Remove HTML of decayed events
  // Keep it less than 50
  if($('#area svg g').length > 50){
    $('#area svg g:lt(10)').remove();
  }
}
<commit_msg>Add missing commas<commit_after>var eventQueue = [];
var svg;
var element;
var drawingArea;
var width;
var height;
var volume = 0.6;
var ULTIMATE_DREAM_KILLER = false;  // https://github.com/debugger22/github-audio/pull/19
var orgRepoFilterNames = [];

var scale_factor = 6,
    note_overlap = 2,
    note_timeout = 300,
    current_notes = 0,
    max_life = 20000;

var svg_background_color_online = '#0288D1',
    svg_background_color_offline = '#E91E63',
    svg_text_color = '#FFFFFF',
    newuser_box_color = 'rgb(41, 128, 185)',
    push_color = 'rgb(155, 89, 182)',
    issue_color = 'rgb(46, 204, 113)',
    pull_request_color = 'rgb(46, 204, 113)',
    comment_color = 'rgb(46, 204, 113)',
    edit_color = '#fff',
    total_sounds = 51;

    var celesta = [],
        clav = [],
        swells = [],
        all_loaded = false;

var socket = io();
socket.on('github', function (data) {
  $('.online-users-count').html(data.connected_users);
  data.data.forEach(function(event){
    if(!isEventInQueue(event)){
      // Filter out events only specified by the user
      if(orgRepoFilterNames != []){
        // Don't consider pushes to github.io repos when org filter is on
        if(new RegExp(orgRepoFilterNames.join("|")).test(event.repo_name)
           && event.repo_name.indexOf('github.io') == -1){
          eventQueue.push(event);
        }
      }else{
        eventQueue.push(event);
      }
    }
  });
  // Don't let the eventQueue grow more than 1000
  if (eventQueue.length > 1000) eventQueue = eventQueue.slice(0, 1000);
});

socket.on('connect', function(){
    if(svg != null){
      $('svg').css('background-color', svg_background_color_online);
      $('header').css('background-color', svg_background_color_online);
      $('.offline-text').css('visibility', 'hidden');
      $('.events-remaining-text').css('visibility', 'hidden');
      $('.events-remaining-value').css('visibility', 'hidden');
    }
});

socket.on('disconnect', function(){
    if(svg != null){
      $('svg').css('background-color', svg_background_color_offline);
      $('header').css('background-color', svg_background_color_offline);
      $('.offline-text').css('visibility', 'visible');
      $('.events-remaining-text').css('visibility', 'visible');
      $('.events-remaining-value').css('visibility', 'visible');

    }
});

socket.on('error', function(){
    if(svg != null){
      $('svg').css('background-color', svg_background_color_offline);
      $('header').css('background-color', svg_background_color_offline);
      $('.offline-text').css('visibility', 'visible');
      $('.events-remaining-text').css('visibility', 'visible');
      $('.events-remaining-value').css('visibility', 'visible');
    }
});

/**
* This function checks whether an event is already in the queue
*/
function isEventInQueue(event){
  for(var i=0; i<eventQueue.length; i++){
    if(eventQueue[i].id == event.id)
      return true;
  }
  return false;
}

/**
 * This function adds a filter for events that we don't want to hear.
 *
 * To extend this function, simply add return true for events that should be filtered.
 */
function shouldEventBeIgnored(event){
  // This adds an easter egg to only play closed PRs
  if (!!ULTIMATE_DREAM_KILLER)
    return (event.type !== "PullRequestEvent" || event.action !== "closed");

  return false;
}

$(function(){
  element = document.documentElement;
  drawingArea = document.getElementsByTagName('#area')[0];
  width = window.innerWidth || element.clientWidth || drawingArea.clientWidth;
  height = (window.innerHeight  - $('header').height())|| (element.clientHeight - $('header').height()) || (drawingArea.clientHeight - $('header').height());
  $('svg').css('background-color', svg_background_color_online);
  $('header').css('background-color', svg_background_color_online);
  $('svg text').css('color', svg_text_color);
  $('#volumeSlider').slider({
    'max': 100,
    'min': 0,
    'value': volume*100,
    'slide' : function(event, ui){
      volume = ui.value/100.0;
      Howler.volume(volume);
    },
    'change' : function(event, ui){
      volume = ui.value/100.0;
      Howler.volume(volume);
    }
  });

  // Main drawing area
  svg = d3.select("#area").append("svg");
  svg.attr({width: width, height: height});
  svg.style('background-color', svg_background_color_online);

  // For window resizes
  var update_window = function() {
      width = window.innerWidth || element.clientWidth || drawingArea.clientWidth;
      height = (window.innerHeight  - $('header').height())|| (element.clientHeight - $('header').height()) || (drawingArea.clientHeight - $('header').height());
      svg.attr("width", width).attr("height", height);
  }
  window.onresize = update_window;
  update_window();

  var loaded_sounds = 0;
  var sound_load = function(r) {
      loaded_sounds += 1;
      if (loaded_sounds == total_sounds) {
          all_loaded = true;
          setTimeout(playFromQueueExchange1, Math.floor(Math.random() * 1000));
          // Starting the second exchange makes music a bad experience
          // setTimeout(playFromQueueExchange2, Math.floor(Math.random() * 2000));
      }
  }

  // Load sounds
  for (var i = 1; i <= 24; i++) {
      if (i > 9) {
          fn = 'c0' + i;
      } else {
          fn = 'c00' + i;
      }
      celesta.push(new Howl({
          src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/celesta/' + fn + '.ogg',
                  'https://d1fz9d31zqor6x.cloudfront.net/sounds/celesta/' + fn + '.mp3'],
          volume : 0.7,
          onload : sound_load(),
          buffer: true,
      }))
      clav.push(new Howl({
          src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/clav/' + fn + '.ogg',
                  'https://d1fz9d31zqor6x.cloudfront.net/sounds/clav/' + fn + '.mp3'],
          volume : 0.4,
          onload : sound_load(),
          buffer: true,
      }))
  }

  for (var i = 1; i <= 3; i++) {
      swells.push(new Howl({
          src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/swells/swell' + i + '.ogg',
                  'https://d1fz9d31zqor6x.cloudfront.net/sounds/swells/swell' + i + '.mp3'],
          volume : 1,
          onload : sound_load(),
          buffer: true,
      }));
  }

  Howler.volume(volume);

  // Make header and footer visible
  $('body').css('visibility', 'visible');

  $('#org-repo-filter-name').on('input', function() {
    orgRepoFilterNames = $('#org-repo-filter-name').val().split(' ');
    eventQueue = [];
  });

});

/**
* Randomly selects a swell sound and plays it
*/
function playRandomSwell() {
    var index = Math.round(Math.random() * (swells.length - 1));
    swells[index].play();
}

/**
* Plays a sound(celesta and clav) based on passed parameters
*/
function playSound(size, type) {
    var max_pitch = 100.0;
    var log_used = 1.0715307808111486871978099;
    var pitch = 100 - Math.min(max_pitch, Math.log(size + log_used) / Math.log(log_used));
    var index = Math.floor(pitch / 100.0 * Object.keys(celesta).length);
    var fuzz = Math.floor(Math.random() * 4) - 2;
    index += fuzz;
    index = Math.min(Object.keys(celesta).length - 1, index);
    index = Math.max(1, index);
    if (current_notes < note_overlap) {
        current_notes++;
        if (type == 'IssuesEvent' || type == 'IssueCommentEvent') {
            clav[index].play();
        } else if(type == 'PushEvent') {
            celesta[index].play();
        }else{
          playRandomSwell();
        }
        setTimeout(function() {
            current_notes--;
        }, note_timeout);
    }
}

// Following are the n numbers of event consumers
// consuming n events each per second with a random delay between them

function playFromQueueExchange1(){
  var event = eventQueue.shift();
  if(event != null && event.message != null && !shouldEventBeIgnored(event) && svg != null){
    playSound(event.message.length*1.1, event.type);
    if(!document.hidden)
      drawEvent(event, svg);
  }
  setTimeout(playFromQueueExchange1, Math.floor(Math.random() * 1000) + 500);
  $('.events-remaining-value').html(eventQueue.length);
}

function playFromQueueExchange2(){
  var event = eventQueue.shift();
  if(event != null && event.message != null && !shouldEventBeIgnored(event) && svg != null){
    playSound(event.message.length, event.type);
    if(!document.hidden)
      drawEvent(event, svg);
  }
  setTimeout(playFromQueueExchange2, Math.floor(Math.random() * 800) + 500);
  $('.events-remaining-value').html(eventQueue.length);
}

// This method capitalizes the string in place
String.prototype.capitalize=function(all){
    if(all){
      return this.split(' ').map(function(e){
        return e.capitalize().join(' ');
      });
    }else{
         return this.charAt(0).toUpperCase() + this.slice(1);
    }
}

function drawEvent(data, svg_area) {
    var starting_opacity = 1;
    var opacity = 1 / (100 / data.message.length);
    if (opacity > 0.5) {
        opacity = 0.5;
    }
    var size = data.message.length;
    var label_text;
    var ring_radius = 80;
    var ring_anim_duration = 3000;
    svg_text_color = '#FFFFFF';
    switch(data.type){
      case "PushEvent":
        label_text = data.user.capitalize() + " pushed to " + data.repo_name;
        edit_color = '#B2DFDB';
      break;
      case "PullRequestEvent":
        label_text = data.user.capitalize() + " " +
          data.action + " " + " a PR for " + data.repo_name;
          edit_color = '#C6FF00';
          ring_anim_duration = 10000;
          ring_radius = 600;
      break;
      case "IssuesEvent":
        label_text = data.user.capitalize() + " " +
          data.action + " an issue in " + data.repo_name;
          edit_color = '#FFEB3B';
      break;
      case "IssueCommentEvent":
        label_text = data.user.capitalize() + " commented in " + data.repo_name;
        edit_color = '#FF5722';
      break;
    }
    var csize = size;
    var no_label = false;
    var type = data.type;

    var circle_id = 'd' + ((Math.random() * 100000) | 0);
    var abs_size = Math.abs(size);
    size = Math.max(Math.sqrt(abs_size) * scale_factor, 3);

    Math.seedrandom(data.message)
    var x = Math.random() * (width - size) + size;
    var y = Math.random() * (height - size) + size;

    var circle_group = svg_area.append('g')
        .attr('transform', 'translate(' + x + ', ' + y + ')')
        .attr('fill', edit_color)
        .style('opacity', starting_opacity)

    var ring = circle_group.append('circle');
    ring.attr({r: size, stroke: 'none'});
    ring.transition()
        .attr('r', size + ring_radius)
        .style('opacity', 0)
        .ease(Math.sqrt)
        .duration(ring_anim_duration)
        .remove();

    var circle_container = circle_group.append('a');
    circle_container.attr('xlink:href', data.url);
    circle_container.attr('target', '_blank');
    circle_container.attr('fill', svg_text_color);

    var circle = circle_container.append('circle');
    circle.classed(type, true);
    circle.attr('r', size)
      .attr('fill', edit_color)
      .transition()
      .duration(max_life)
      .style('opacity', 0)
      .remove();

    circle_container.on('mouseover', function() {
      circle_container.append('text')
          .text(label_text)
          .classed('label', true)
          .attr('text-anchor', 'middle')
          .attr('font-size', '0.8em')
          .transition()
          .delay(1000)
          .style('opacity', 0)
          .duration(2000)
          .each(function() { no_label = true; })
          .remove();
    });

    var text = circle_container.append('text')
        .text(label_text)
        .classed('article-label', true)
        .attr('text-anchor', 'middle')
        .attr('font-size', '0.8em')
        .transition()
        .delay(2000)
        .style('opacity', 0)
        .duration(5000)
        .each(function() { no_label = true; })
        .remove();

  // Remove HTML of decayed events
  // Keep it less than 50
  if($('#area svg g').length > 50){
    $('#area svg g:lt(10)').remove();
  }
}
<|endoftext|>


<commit_before>var eventQueue = [];
var svg;
var element;
var drawingArea;
var width;
var height;
var mute = false;
var volume = 0.6;

var scale_factor = 6,
    note_overlap = 2,
    note_timeout = 300,
    current_notes = 0,
    max_life = 20000;

var svg_background_color_online = '#0288D1',
    svg_background_color_offline = '#E91E63'
    svg_text_color = '#FFFFFF',
    newuser_box_color = 'rgb(41, 128, 185)',
    push_color = 'rgb(155, 89, 182)',
    issue_color = 'rgb(46, 204, 113)',
    pull_request_color = 'rgb(46, 204, 113)',
    comment_color = 'rgb(46, 204, 113)'
    edit_color = '#fff',
    total_sounds = 51,
    total_edits = 0;

    var celesta = [],
        clav = [],
        swells = [],
        all_loaded = false;

var socket = io(document.location.hostname);
socket.on('github', function (data) {
  $('.online-users-count').html(data.connected_users);
  data.data.forEach(function(event){
    if(!isEventInQueue(event)){
      eventQueue.push(event);
    }
  });
  // Don't let the eventQueue grow more than 100
  if (eventQueue.length > 100) eventQueue = eventQueue.slice(0, 100);
});

socket.on('connect', function(){
    if(svg != null){
      $('svg').css('background-color', svg_background_color_online);
      $('header').css('background-color', svg_background_color_online);
      $('.offline-text').css('visibility', 'hidden');
      $('.events-remaining-text').css('visibility', 'hidden');
      $('.events-remaining-value').css('visibility', 'hidden');
    }
});

socket.on('disconnect', function(){
    if(svg != null){
      $('svg').css('background-color', svg_background_color_offline);
      $('header').css('background-color', svg_background_color_offline);
      $('.offline-text').css('visibility', 'visible');
      $('.events-remaining-text').css('visibility', 'visible');
      $('.events-remaining-value').css('visibility', 'visible');

    }
});

socket.on('error', function(){
    if(svg != null){
      $('svg').css('background-color', svg_background_color_offline);
      $('header').css('background-color', svg_background_color_offline);
      $('.offline-text').css('visibility', 'visible');
      $('.events-remaining-text').css('visibility', 'visible');
      $('.events-remaining-value').css('visibility', 'visible');
    }
});

/**
* This function checks whether an event is already in the queue
*/
function isEventInQueue(event){
  for(var i=0; i<eventQueue.length; i++){
    if(eventQueue[i].id == event.id)
      return true;
  }
  return false;
}

$(function(){
  element = document.documentElement;
  drawingArea = document.getElementsByTagName('#area')[0];
  width = window.innerWidth || element.clientWidth || drawingArea.clientWidth;
  height = (window.innerHeight  - $('header').height())|| (element.clientHeight - $('header').height()) || (drawingArea.clientHeight - $('header').height());
  $('svg').css('background-color', svg_background_color_online);
  $('header').css('background-color', svg_background_color_online);
  $('svg text').css('color', svg_text_color);
  $('#volumeSlider').slider({
    'max': 100,
    'min': 0,
    'value': volume*100,
    'slide' : function(event, ui){
      volume = ui.value/100.0;
      Howler.volume(volume);
    },
    'change' : function(event, ui){
      volume = ui.value/100.0;
      Howler.volume(volume);
    }
  });

  $('#eventConsumptionSlider').slider({
    'min': 1,
    'max': 100
  });

  // Main drawing area
  svg = d3.select("#area").append("svg");
  svg.attr({width: width, height: height});
  svg.style('background-color', svg_background_color_online);

  // For window resizes
  var update_window = function() {
      width = window.innerWidth || element.clientWidth || drawingArea.clientWidth;
      height = (window.innerHeight  - $('header').height())|| (element.clientHeight - $('header').height()) || (drawingArea.clientHeight - $('header').height());
      svg.attr("width", width).attr("height", height);
  }
  window.onresize = update_window;
  update_window();

  var loaded_sounds = 0;
  var sound_load = function(r) {
      loaded_sounds += 1;
      if (loaded_sounds == total_sounds) {
          all_loaded = true;
          setTimeout(playFromQueueExchange1, Math.floor(Math.random() * 1000));
          // Starting the second exchange makes music a bad experience
          // setTimeout(playFromQueueExchange2, Math.floor(Math.random() * 2000));
      }
  }

  // Load sounds
  for (var i = 1; i <= 24; i++) {
      if (i > 9) {
          fn = 'c0' + i;
      } else {
          fn = 'c00' + i;
      }
      celesta.push(new Howl({
          src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/celesta/' + fn + '.ogg',
                  'https://d1fz9d31zqor6x.cloudfront.net/sounds/celesta/' + fn + '.mp3'],
          volume : 0.7,
          onload : sound_load(),
          buffer: true,
      }))
      clav.push(new Howl({
          src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/clav/' + fn + '.ogg',
                  'https://d1fz9d31zqor6x.cloudfront.net/sounds/clav/' + fn + '.mp3'],
          volume : 0.4,
          onload : sound_load(),
          buffer: true,
      }))
  }

  for (var i = 1; i <= 3; i++) {
      swells.push(new Howl({
          src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/swells/swell' + i + '.ogg',
                  'https://d1fz9d31zqor6x.cloudfront.net/sounds/swells/swell' + i + '.mp3'],
          volume : 1,
          onload : sound_load(),
          buffer: true,
      }));
  }

  Howler.volume(volume);

});

/**
* Randomly selects a swell sound and plays it
*/
function playRandomSwell() {
    var index = Math.round(Math.random() * (swells.length - 1));
    swells[index].play();
}

/**
* Plays a sound(celesta and clav) based on passed parameters
*/
function playSound(size, type) {
    var max_pitch = 100.0;
    var log_used = 1.0715307808111486871978099;
    var pitch = 100 - Math.min(max_pitch, Math.log(size + log_used) / Math.log(log_used));
    var index = Math.floor(pitch / 100.0 * Object.keys(celesta).length);
    var fuzz = Math.floor(Math.random() * 4) - 2;
    index += fuzz;
    index = Math.min(Object.keys(celesta).length - 1, index);
    index = Math.max(1, index);
    if (current_notes < note_overlap) {
        current_notes++;
        if (type == 'IssuesEvent' || type == 'IssueCommentEvent') {
            clav[index].play();
        } else if(type == 'PushEvent') {
            celesta[index].play();
        }else{
          playRandomSwell();
        }
        setTimeout(function() {
            current_notes--;
        }, note_timeout);
    }
}

// Following are the n numbers of event consumers
// consuming n events each per second with a random delay between them

function playFromQueueExchange1(){
  var event = eventQueue.shift();
  if(event != null && event.message != null && svg != null){
    if(!mute)
      playSound(event.message.length*1.1, event.type);
    if(!document.hidden)
      drawEvent(event, svg);
  }
  setTimeout(playFromQueueExchange1, Math.floor(Math.random() * 1000) + 500);
  $('.events-remaining-value').html(eventQueue.length);
}

function playFromQueueExchange2(){
  var event = eventQueue.shift();
  if(event != null && event.message != null && svg != null){
    if(!mute)
      playSound(event.message.length, event.type);
    if(!document.hidden)
      drawEvent(event, svg);
  }
  setTimeout(playFromQueueExchange2, Math.floor(Math.random() * 800) + 500);
  $('.events-remaining-value').html(eventQueue.length);
}

// This method capitalizes the string in place
String.prototype.capitalize=function(all){
    if(all){
      return this.split(' ').map(function(e){
        return e.capitalize().join(' ');
      });
    }else{
         return this.charAt(0).toUpperCase() + this.slice(1);
    }
}

function drawEvent(data, svg_area) {
    var starting_opacity = 1;
    var opacity = 1 / (100 / data.message.length);
    if (opacity > 0.5) {
        opacity = 0.5;
    }
    var size = data.message.length;
    var label_text;
    var ring_radius = 80;
    var ring_anim_duration = 3000;
    svg_text_color = '#FFFFFF';
    switch(data.type){
      case "PushEvent":
        label_text = data.user.capitalize() + " pushed to " + data.repo_name;
        edit_color = '#B2DFDB';
      break;
      case "PullRequestEvent":
        label_text = data.user.capitalize() + " " +
          data.action + " " + " a PR for " + data.repo_name;
          edit_color = '#C6FF00';
          ring_anim_duration = 10000;
          ring_radius = 600;
      break;
      case "IssuesEvent":
        label_text = data.user.capitalize() + " " +
          data.action + " an issue in " + data.repo_name;
          edit_color = '#FFEB3B';
      break;
      case "IssueCommentEvent":
        label_text = data.user.capitalize() + " commented in " + data.repo_name;
        edit_color = '#FF5722';
      break;
    }
    var csize = size;
    var no_label = false;
    var type = data.type;

    var circle_id = 'd' + ((Math.random() * 100000) | 0);
    var abs_size = Math.abs(size);
    size = Math.max(Math.sqrt(abs_size) * scale_factor, 3);

    Math.seedrandom(data.message)
    var x = Math.random() * (width - size) + size;
    var y = Math.random() * (height - size) + size;

    var circle_group = svg_area.append('g')
        .attr('transform', 'translate(' + x + ', ' + y + ')')
        .attr('fill', edit_color)
        .style('opacity', starting_opacity)

    var ring = circle_group.append('circle');
    ring.attr({r: size, stroke: 'none'});
    ring.transition()
        .attr('r', size + ring_radius)
        .style('opacity', 0)
        .ease(Math.sqrt)
        .duration(ring_anim_duration)
        .remove();

    var circle_container = circle_group.append('a');
    circle_container.attr('xlink:href', 'https://github.com/' + data.repo_name);
    circle_container.attr('target', '_blank');
    circle_container.attr('fill', svg_text_color);

    var circle = circle_container.append('circle');
    circle.classed(type, true);
    circle.attr('r', size)
      .attr('fill', edit_color)
      .transition()
      .duration(max_life)
      .style('opacity', 0)
      .remove();

    circle_container.on('mouseover', function() {
      circle_container.append('text')
          .text(label_text)
          .classed('label', true)
          .attr('text-anchor', 'middle')
          .attr('font-size', '0.8em')
          .transition()
          .delay(1000)
          .style('opacity', 0)
          .duration(2000)
          .each(function() { no_label = true; })
          .remove();
    });

    var text = circle_container.append('text')
        .text(label_text)
        .classed('article-label', true)
        .attr('text-anchor', 'middle')
        .attr('font-size', '0.8em')
        .transition()
        .delay(2000)
        .style('opacity', 0)
        .duration(5000)
        .each(function() { no_label = true; })
        .remove();

  // Remove HTML of decayed events
  // Keep it less than 50
  if($('#area svg g').length > 50){
    $('#area svg g:lt(10)').remove();
  }
}

// Some hack to start Howler.js it on iPhone
var unlockIOSAudioPlayback = function () {
    var context = Howler.ctx;
    var oscillator = context.createOscillator();
    oscillator.frequency.value = 200;
    oscillator.connect(context.destination);
    oscillator.start(0);
    oscillator.stop(0);
};
<commit_msg>Revert sound hack for iPhone. Didn't work! :/<commit_after>var eventQueue = [];
var svg;
var element;
var drawingArea;
var width;
var height;
var mute = false;
var volume = 0.6;

var scale_factor = 6,
    note_overlap = 2,
    note_timeout = 300,
    current_notes = 0,
    max_life = 20000;

var svg_background_color_online = '#0288D1',
    svg_background_color_offline = '#E91E63'
    svg_text_color = '#FFFFFF',
    newuser_box_color = 'rgb(41, 128, 185)',
    push_color = 'rgb(155, 89, 182)',
    issue_color = 'rgb(46, 204, 113)',
    pull_request_color = 'rgb(46, 204, 113)',
    comment_color = 'rgb(46, 204, 113)'
    edit_color = '#fff',
    total_sounds = 51,
    total_edits = 0;

    var celesta = [],
        clav = [],
        swells = [],
        all_loaded = false;

var socket = io(document.location.hostname);
socket.on('github', function (data) {
  $('.online-users-count').html(data.connected_users);
  data.data.forEach(function(event){
    if(!isEventInQueue(event)){
      eventQueue.push(event);
    }
  });
  // Don't let the eventQueue grow more than 100
  if (eventQueue.length > 100) eventQueue = eventQueue.slice(0, 100);
});

socket.on('connect', function(){
    if(svg != null){
      $('svg').css('background-color', svg_background_color_online);
      $('header').css('background-color', svg_background_color_online);
      $('.offline-text').css('visibility', 'hidden');
      $('.events-remaining-text').css('visibility', 'hidden');
      $('.events-remaining-value').css('visibility', 'hidden');
    }
});

socket.on('disconnect', function(){
    if(svg != null){
      $('svg').css('background-color', svg_background_color_offline);
      $('header').css('background-color', svg_background_color_offline);
      $('.offline-text').css('visibility', 'visible');
      $('.events-remaining-text').css('visibility', 'visible');
      $('.events-remaining-value').css('visibility', 'visible');

    }
});

socket.on('error', function(){
    if(svg != null){
      $('svg').css('background-color', svg_background_color_offline);
      $('header').css('background-color', svg_background_color_offline);
      $('.offline-text').css('visibility', 'visible');
      $('.events-remaining-text').css('visibility', 'visible');
      $('.events-remaining-value').css('visibility', 'visible');
    }
});

/**
* This function checks whether an event is already in the queue
*/
function isEventInQueue(event){
  for(var i=0; i<eventQueue.length; i++){
    if(eventQueue[i].id == event.id)
      return true;
  }
  return false;
}

$(function(){
  element = document.documentElement;
  drawingArea = document.getElementsByTagName('#area')[0];
  width = window.innerWidth || element.clientWidth || drawingArea.clientWidth;
  height = (window.innerHeight  - $('header').height())|| (element.clientHeight - $('header').height()) || (drawingArea.clientHeight - $('header').height());
  $('svg').css('background-color', svg_background_color_online);
  $('header').css('background-color', svg_background_color_online);
  $('svg text').css('color', svg_text_color);
  $('#volumeSlider').slider({
    'max': 100,
    'min': 0,
    'value': volume*100,
    'slide' : function(event, ui){
      volume = ui.value/100.0;
      Howler.volume(volume);
    },
    'change' : function(event, ui){
      volume = ui.value/100.0;
      Howler.volume(volume);
    }
  });

  $('#eventConsumptionSlider').slider({
    'min': 1,
    'max': 100
  });

  // Main drawing area
  svg = d3.select("#area").append("svg");
  svg.attr({width: width, height: height});
  svg.style('background-color', svg_background_color_online);

  // For window resizes
  var update_window = function() {
      width = window.innerWidth || element.clientWidth || drawingArea.clientWidth;
      height = (window.innerHeight  - $('header').height())|| (element.clientHeight - $('header').height()) || (drawingArea.clientHeight - $('header').height());
      svg.attr("width", width).attr("height", height);
  }
  window.onresize = update_window;
  update_window();

  var loaded_sounds = 0;
  var sound_load = function(r) {
      loaded_sounds += 1;
      if (loaded_sounds == total_sounds) {
          all_loaded = true;
          setTimeout(playFromQueueExchange1, Math.floor(Math.random() * 1000));
          // Starting the second exchange makes music a bad experience
          // setTimeout(playFromQueueExchange2, Math.floor(Math.random() * 2000));
      }
  }

  // Load sounds
  for (var i = 1; i <= 24; i++) {
      if (i > 9) {
          fn = 'c0' + i;
      } else {
          fn = 'c00' + i;
      }
      celesta.push(new Howl({
          src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/celesta/' + fn + '.ogg',
                  'https://d1fz9d31zqor6x.cloudfront.net/sounds/celesta/' + fn + '.mp3'],
          volume : 0.7,
          onload : sound_load(),
          buffer: true,
      }))
      clav.push(new Howl({
          src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/clav/' + fn + '.ogg',
                  'https://d1fz9d31zqor6x.cloudfront.net/sounds/clav/' + fn + '.mp3'],
          volume : 0.4,
          onload : sound_load(),
          buffer: true,
      }))
  }

  for (var i = 1; i <= 3; i++) {
      swells.push(new Howl({
          src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/swells/swell' + i + '.ogg',
                  'https://d1fz9d31zqor6x.cloudfront.net/sounds/swells/swell' + i + '.mp3'],
          volume : 1,
          onload : sound_load(),
          buffer: true,
      }));
  }

  Howler.volume(volume);

});

/**
* Randomly selects a swell sound and plays it
*/
function playRandomSwell() {
    var index = Math.round(Math.random() * (swells.length - 1));
    swells[index].play();
}

/**
* Plays a sound(celesta and clav) based on passed parameters
*/
function playSound(size, type) {
    var max_pitch = 100.0;
    var log_used = 1.0715307808111486871978099;
    var pitch = 100 - Math.min(max_pitch, Math.log(size + log_used) / Math.log(log_used));
    var index = Math.floor(pitch / 100.0 * Object.keys(celesta).length);
    var fuzz = Math.floor(Math.random() * 4) - 2;
    index += fuzz;
    index = Math.min(Object.keys(celesta).length - 1, index);
    index = Math.max(1, index);
    if (current_notes < note_overlap) {
        current_notes++;
        if (type == 'IssuesEvent' || type == 'IssueCommentEvent') {
            clav[index].play();
        } else if(type == 'PushEvent') {
            celesta[index].play();
        }else{
          playRandomSwell();
        }
        setTimeout(function() {
            current_notes--;
        }, note_timeout);
    }
}

// Following are the n numbers of event consumers
// consuming n events each per second with a random delay between them

function playFromQueueExchange1(){
  var event = eventQueue.shift();
  if(event != null && event.message != null && svg != null){
    if(!mute)
      playSound(event.message.length*1.1, event.type);
    if(!document.hidden)
      drawEvent(event, svg);
  }
  setTimeout(playFromQueueExchange1, Math.floor(Math.random() * 1000) + 500);
  $('.events-remaining-value').html(eventQueue.length);
}

function playFromQueueExchange2(){
  var event = eventQueue.shift();
  if(event != null && event.message != null && svg != null){
    if(!mute)
      playSound(event.message.length, event.type);
    if(!document.hidden)
      drawEvent(event, svg);
  }
  setTimeout(playFromQueueExchange2, Math.floor(Math.random() * 800) + 500);
  $('.events-remaining-value').html(eventQueue.length);
}

// This method capitalizes the string in place
String.prototype.capitalize=function(all){
    if(all){
      return this.split(' ').map(function(e){
        return e.capitalize().join(' ');
      });
    }else{
         return this.charAt(0).toUpperCase() + this.slice(1);
    }
}

function drawEvent(data, svg_area) {
    var starting_opacity = 1;
    var opacity = 1 / (100 / data.message.length);
    if (opacity > 0.5) {
        opacity = 0.5;
    }
    var size = data.message.length;
    var label_text;
    var ring_radius = 80;
    var ring_anim_duration = 3000;
    svg_text_color = '#FFFFFF';
    switch(data.type){
      case "PushEvent":
        label_text = data.user.capitalize() + " pushed to " + data.repo_name;
        edit_color = '#B2DFDB';
      break;
      case "PullRequestEvent":
        label_text = data.user.capitalize() + " " +
          data.action + " " + " a PR for " + data.repo_name;
          edit_color = '#C6FF00';
          ring_anim_duration = 10000;
          ring_radius = 600;
      break;
      case "IssuesEvent":
        label_text = data.user.capitalize() + " " +
          data.action + " an issue in " + data.repo_name;
          edit_color = '#FFEB3B';
      break;
      case "IssueCommentEvent":
        label_text = data.user.capitalize() + " commented in " + data.repo_name;
        edit_color = '#FF5722';
      break;
    }
    var csize = size;
    var no_label = false;
    var type = data.type;

    var circle_id = 'd' + ((Math.random() * 100000) | 0);
    var abs_size = Math.abs(size);
    size = Math.max(Math.sqrt(abs_size) * scale_factor, 3);

    Math.seedrandom(data.message)
    var x = Math.random() * (width - size) + size;
    var y = Math.random() * (height - size) + size;

    var circle_group = svg_area.append('g')
        .attr('transform', 'translate(' + x + ', ' + y + ')')
        .attr('fill', edit_color)
        .style('opacity', starting_opacity)

    var ring = circle_group.append('circle');
    ring.attr({r: size, stroke: 'none'});
    ring.transition()
        .attr('r', size + ring_radius)
        .style('opacity', 0)
        .ease(Math.sqrt)
        .duration(ring_anim_duration)
        .remove();

    var circle_container = circle_group.append('a');
    circle_container.attr('xlink:href', 'https://github.com/' + data.repo_name);
    circle_container.attr('target', '_blank');
    circle_container.attr('fill', svg_text_color);

    var circle = circle_container.append('circle');
    circle.classed(type, true);
    circle.attr('r', size)
      .attr('fill', edit_color)
      .transition()
      .duration(max_life)
      .style('opacity', 0)
      .remove();

    circle_container.on('mouseover', function() {
      circle_container.append('text')
          .text(label_text)
          .classed('label', true)
          .attr('text-anchor', 'middle')
          .attr('font-size', '0.8em')
          .transition()
          .delay(1000)
          .style('opacity', 0)
          .duration(2000)
          .each(function() { no_label = true; })
          .remove();
    });

    var text = circle_container.append('text')
        .text(label_text)
        .classed('article-label', true)
        .attr('text-anchor', 'middle')
        .attr('font-size', '0.8em')
        .transition()
        .delay(2000)
        .style('opacity', 0)
        .duration(5000)
        .each(function() { no_label = true; })
        .remove();

  // Remove HTML of decayed events
  // Keep it less than 50
  if($('#area svg g').length > 50){
    $('#area svg g:lt(10)').remove();
  }
}
<|endoftext|>


<commit_before>import Ember from 'ember';
import ResetScrollMixin from '../mixins/reset-scroll';
import SetupSubmitControllerMixin from '../mixins/setup-submit-controller';
import Analytics from '../mixins/analytics';
import config from 'ember-get-config';
import loadAll from 'ember-osf/utils/load-relationship';
import permissions from 'ember-osf/const/permissions';

export default Ember.Route.extend(Analytics, ResetScrollMixin, SetupSubmitControllerMixin, {
    theme: Ember.inject.service(),
    headTagsService: Ember.inject.service('head-tags'),
    currentUser: Ember.inject.service('currentUser'),
    queryParams: {
        edit: {
            refreshModel: true // if queryParam, do a full transition
        }
    },
    setup() {
        // Overrides setup method.  If query param /?edit is present, uses 'submit' controller instead.
        this.set('controllerName', this.get('editMode') ? 'submit' : 'content');
        return this._super(...arguments);
    },
    renderTemplate() {
        // Overrides renderTemplate method.  If query param /?edit is present, uses 'submit' template instead.
        this.render(this.get('editMode') ? 'submit' : 'content');
    },
    model(params) {
        if (params.edit)
            this.set('editMode', true);

        return this
            .store
            .findRecord('preprint', params.preprint_id);
    },
    setupController(controller, model) {
        if (this.get('editMode')) {
            // Runs setupController for 'submit'
            this.setupSubmitController(controller, model);
        } else {
            // Runs setupController for 'content'
            controller.set('activeFile', model.get('primaryFile'));
            controller.set('node', this.get('node'));
            Ember.run.scheduleOnce('afterRender', this, function() {
                MathJax.Hub.Queue(['Typeset', MathJax.Hub, [Ember.$('.abstract')[0], Ember.$('#preprintTitle')[0]]]);  // jshint ignore:line
            });
        }

        return this._super(...arguments);
    },
    afterModel(preprint) {
        // Redirect if necessary
        preprint.get('provider')
            .then(provider => {
                const providerId = provider.get('id');
                const themeId = this.get('theme.id');
                const isOSF = providerId === 'osf';

                // If we're on the proper branded site, stay there.
                if ((!themeId && isOSF) || themeId === providerId)
                    return;

                // Otherwise, redirect to the branded page
                // Hard redirect instead of transition, in anticipation of Phase 2 where providers will have their own domains.
                const {origin, search} = window.location;

                const urlParts = [
                    origin
                ];

                if (!isOSF)
                    urlParts.push('preprints', providerId);

                urlParts.push(preprint.get('id'), search);

                const url = urlParts.join('/');

                window.history.replaceState({}, document.title, url);
                window.location.replace(url);
            });

        return preprint.get('node').then(node => {
            this.set('node', node);

            if (this.get('editMode')) {
                let userPermissions = this.get('node.currentUserPermissions') || [];
                if (userPermissions.indexOf(permissions.ADMIN) === -1) {
                    this.replaceWith('forbidden'); // Non-admin trying to access edit form.
                }
            }

            const {origin} = window.location;
            const image = this.get('theme.logoSharing');
            const imageUrl = `${origin.replace(/^https/, 'http')}${image.path}`;
            const d = new Date(preprint.get('dateCreated'));
            const ogp = [
                ['fb:app_id', config.FB_APP_ID],
                ['og:title', node.get('title')],
                ['og:image', imageUrl],
                ['og:image:secure_url', `${origin}${image.path}`], // We should always be on https in staging/prod
                ['og:image:width', image.width.toString()],
                ['og:image:height', image.height.toString()],
                ['og:image:type', image.type],
                ['og:url', window.location.href],
                ['og:description', node.get('description')],
                ['og:site_name', this.get('theme.provider.name')],
                ['og:type', 'article'],
                ['article:published_time', d.toISOString()],
                ['article:modified_time', new Date(preprint.get('dateModified')).toISOString()],
                ['citation_title', node.get('title')],
                ['citation_description', node.get('description')],
                ['citation_public_url', window.location.href],
                ['citation_publication_date', `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}`],
                ['citation_doi', preprint.get('doi')],
                ['dc.title', node.get('title')],
                ['dc.abstract', node.get('description')],
                ['dc.identifier', window.location.href],
                ['dc.identifier', preprint.get('doi')],
            ];

            const tags = [
                ...preprint.get('subjects').map(subjectBlock => subjectBlock.map(subject => subject.text)),
                ...node.get('tags')
            ];

            for (const tag of tags)
                ogp.push(
                    ['article:tag', tag],
                    ['citation_keywords', tag],
                    ['dc.subject', tag]
                );

            let contributors = Ember.A();

            loadAll(node, 'contributors', contributors).then(() => {
                contributors.forEach(contributor => {
                    ogp.push(
                        ['og:type', 'article:author'],
                        ['profile:first_name', contributor.get('users.givenName')],
                        ['profile:last_name', contributor.get('users.familyName')],
                        ['citation_author', `${contributor.get('users.givenName')} ${contributor.get('users.familyName')}`],
                        ['dc.creator', `${contributor.get('users.givenName')} ${contributor.get('users.familyName')}`]
                    );
                });

                this.set('headTags', ogp.map(item => (
                    {
                        type: 'meta',
                        attrs: {
                            property: item[0],
                            content: item[1]
                        }
                    }
                )));

                this.get('headTagsService').collectHeadTags();

                preprint.get('provider').then(provider => {
                    ogp.push(
                        ['citation_publisher', provider.get('name')],
                        ['dc.publisher', provider.get('name')]
                    );
                    preprint.get('license').then(license => {
                        ogp.push(
                            ['dc.license', license.get('name')]
                        );
                        preprint.get('primaryFile').then(file => {
                            if (file.get('name').split('.').pop() === 'pdf') {
                                ogp.push(
                                    ['citation_pdf_url', file.get('links').download]
                                );
                            }
                            this.set('headTags', ogp.map(item => (
                                {
                                    type: 'meta',
                                    attrs: {
                                        property: item[0],
                                        content: item[1]
                                    }
                                }
                            )));
                            this.get('headTagsService').collectHeadTags();
                        });
                    });
                });
            });
        });
    },
    actions: {
        error(error, transition) {
            if (error && error.errors && Ember.isArray(error.errors) && error.errors[0].detail === 'The requested node is no longer available.') {
                this.intermediateTransitionTo('resource-deleted'); // Node containing preprint has been deleted. 410 Gone.
            } else {
                const slug = transition.params[transition.targetName].preprint_id;

                if (slug.length === 5) {
                    window.location.href = [
                        window.location.origin,
                        slug
                    ].join('/');
                } else {
                    const path = ['', 'preprints'];

                    if (this.get('theme.isProvider'))
                        path.push(this.get('theme.id'));

                    path.push(slug);

                    window.history.replaceState({}, 'preprints', path.join('/'));
                    this.intermediateTransitionTo('page-not-found');
                }
            }
        }
    }
});
<commit_msg>Use preprint.get('links.html') over window.location and better var name (d-> dateCreated)<commit_after>import Ember from 'ember';
import ResetScrollMixin from '../mixins/reset-scroll';
import SetupSubmitControllerMixin from '../mixins/setup-submit-controller';
import Analytics from '../mixins/analytics';
import config from 'ember-get-config';
import loadAll from 'ember-osf/utils/load-relationship';
import permissions from 'ember-osf/const/permissions';

export default Ember.Route.extend(Analytics, ResetScrollMixin, SetupSubmitControllerMixin, {
    theme: Ember.inject.service(),
    headTagsService: Ember.inject.service('head-tags'),
    currentUser: Ember.inject.service('currentUser'),
    queryParams: {
        edit: {
            refreshModel: true // if queryParam, do a full transition
        }
    },
    setup() {
        // Overrides setup method.  If query param /?edit is present, uses 'submit' controller instead.
        this.set('controllerName', this.get('editMode') ? 'submit' : 'content');
        return this._super(...arguments);
    },
    renderTemplate() {
        // Overrides renderTemplate method.  If query param /?edit is present, uses 'submit' template instead.
        this.render(this.get('editMode') ? 'submit' : 'content');
    },
    model(params) {
        if (params.edit)
            this.set('editMode', true);

        return this
            .store
            .findRecord('preprint', params.preprint_id);
    },
    setupController(controller, model) {
        if (this.get('editMode')) {
            // Runs setupController for 'submit'
            this.setupSubmitController(controller, model);
        } else {
            // Runs setupController for 'content'
            controller.set('activeFile', model.get('primaryFile'));
            controller.set('node', this.get('node'));
            Ember.run.scheduleOnce('afterRender', this, function() {
                MathJax.Hub.Queue(['Typeset', MathJax.Hub, [Ember.$('.abstract')[0], Ember.$('#preprintTitle')[0]]]);  // jshint ignore:line
            });
        }

        return this._super(...arguments);
    },
    afterModel(preprint) {
        // Redirect if necessary
        preprint.get('provider')
            .then(provider => {
                const providerId = provider.get('id');
                const themeId = this.get('theme.id');
                const isOSF = providerId === 'osf';

                // If we're on the proper branded site, stay there.
                if ((!themeId && isOSF) || themeId === providerId)
                    return;

                // Otherwise, redirect to the branded page
                // Hard redirect instead of transition, in anticipation of Phase 2 where providers will have their own domains.
                const {origin, search} = window.location;

                const urlParts = [
                    origin
                ];

                if (!isOSF)
                    urlParts.push('preprints', providerId);

                urlParts.push(preprint.get('id'), search);

                const url = urlParts.join('/');

                window.history.replaceState({}, document.title, url);
                window.location.replace(url);
            });

        return preprint.get('node').then(node => {
            this.set('node', node);

            if (this.get('editMode')) {
                let userPermissions = this.get('node.currentUserPermissions') || [];
                if (userPermissions.indexOf(permissions.ADMIN) === -1) {
                    this.replaceWith('forbidden'); // Non-admin trying to access edit form.
                }
            }

            const {origin} = window.location;
            const image = this.get('theme.logoSharing');
            const imageUrl = `${origin.replace(/^https/, 'http')}${image.path}`;
            const dateCreated = new Date(preprint.get('dateCreated'));
            const ogp = [
                ['fb:app_id', config.FB_APP_ID],
                ['og:title', node.get('title')],
                ['og:image', imageUrl],
                ['og:image:secure_url', `${origin}${image.path}`], // We should always be on https in staging/prod
                ['og:image:width', image.width.toString()],
                ['og:image:height', image.height.toString()],
                ['og:image:type', image.type],
                ['og:url', preprint.get('links.html')],
                ['og:description', node.get('description')],
                ['og:site_name', this.get('theme.provider.name')],
                ['og:type', 'article'],
                ['article:published_time', dateCreated.toISOString()],
                ['article:modified_time', new Date(preprint.get('dateModified')).toISOString()],
                ['citation_title', node.get('title')],
                ['citation_description', node.get('description')],
                ['citation_public_url', preprint.get('links.html')],
                ['citation_publication_date', `${dateCreated.getFullYear()}/${dateCreated.getMonth() + 1}/${dateCreated.getDate()}`],
                ['citation_doi', preprint.get('doi')],
                ['dc.title', node.get('title')],
                ['dc.abstract', node.get('description')],
                ['dc.identifier', preprint.get('links.html')],
                ['dc.identifier', preprint.get('doi')],
            ];

            const tags = [
                ...preprint.get('subjects').map(subjectBlock => subjectBlock.map(subject => subject.text)),
                ...node.get('tags')
            ];

            for (const tag of tags)
                ogp.push(
                    ['article:tag', tag],
                    ['citation_keywords', tag],
                    ['dc.subject', tag]
                );

            let contributors = Ember.A();

            loadAll(node, 'contributors', contributors).then(() => {
                contributors.forEach(contributor => {
                    ogp.push(
                        ['og:type', 'article:author'],
                        ['profile:first_name', contributor.get('users.givenName')],
                        ['profile:last_name', contributor.get('users.familyName')],
                        ['citation_author', `${contributor.get('users.givenName')} ${contributor.get('users.familyName')}`],
                        ['dc.creator', `${contributor.get('users.givenName')} ${contributor.get('users.familyName')}`]
                    );
                });

                this.set('headTags', ogp.map(item => (
                    {
                        type: 'meta',
                        attrs: {
                            property: item[0],
                            content: item[1]
                        }
                    }
                )));

                this.get('headTagsService').collectHeadTags();

                preprint.get('provider').then(provider => {
                    ogp.push(
                        ['citation_publisher', provider.get('name')],
                        ['dc.publisher', provider.get('name')]
                    );
                    preprint.get('license').then(license => {
                        ogp.push(
                            ['dc.license', license.get('name')]
                        );
                        preprint.get('primaryFile').then(file => {
                            if (file.get('name').split('.').pop() === 'pdf') {
                                ogp.push(
                                    ['citation_pdf_url', file.get('links').download]
                                );
                            }
                            this.set('headTags', ogp.map(item => (
                                {
                                    type: 'meta',
                                    attrs: {
                                        property: item[0],
                                        content: item[1]
                                    }
                                }
                            )));
                            this.get('headTagsService').collectHeadTags();
                        });
                    });
                });
            });
        });
    },
    actions: {
        error(error, transition) {
            if (error && error.errors && Ember.isArray(error.errors) && error.errors[0].detail === 'The requested node is no longer available.') {
                this.intermediateTransitionTo('resource-deleted'); // Node containing preprint has been deleted. 410 Gone.
            } else {
                const slug = transition.params[transition.targetName].preprint_id;

                if (slug.length === 5) {
                    window.location.href = [
                        window.location.origin,
                        slug
                    ].join('/');
                } else {
                    const path = ['', 'preprints'];

                    if (this.get('theme.isProvider'))
                        path.push(this.get('theme.id'));

                    path.push(slug);

                    window.history.replaceState({}, 'preprints', path.join('/'));
                    this.intermediateTransitionTo('page-not-found');
                }
            }
        }
    }
});
<|endoftext|>


<commit_before>/*
    Copyright 2015 Diamond Light Source <stuart.fisher@diamond.ac.uk>

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

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

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

define(['backbone', 'marionette', 'underscore', 'jquery',

    'views/header',
    'views/sidebar',
    'views/dialogregion',
    'views/login',

    'models/proposal',
    'models/options',

    'utils',
    'config.json',
    'jquery.cookie', 'jquery-ui',
        ],
function(Backbone, Marionette, _, $, HeaderView, SideBarView, DialogRegion, LoginView, Proposal, Options, utils, config) {

  window.app = new Marionette.Application()

  console.log('CONFIG', config)

  // Base url for the api
  app.apiurl = config.apiurl

  // Base url for the app
  app.appurl = config.appurl

  // reference to config
  app.config = config

  // Restore token if its in sessionStorage
  app.token = sessionStorage.getItem('token')

  // Allow the app to load a proposal on bootstrap
  app.parseQuery = function() {
      var str = location.search.replace(/\?/, '').split(/&/)
      var pairs = {}
      _.each(str, function(v) {
          var kv = v.split(/=/)
          pairs[kv[0]] = kv[1]
      })

      console.log('pairs', pairs)

      if ('prop' in pairs) sessionStorage.setItem('prop', pairs.prop)
  }

  app.parseQuery()

  // Allow the app to autoupdate itself when running
  app.checkForUpdate = function() {
      Backbone.ajax({
          url: app.appurl+'/js/config.json?t='+(new Date().getTime()),
          success: function(config) {
              console.log('old', app.config.build, 'new', config.build)
              if (config.build != app.config.build) {
                  app.alert({ message: 'An update to SynchWeb is available. This page will automatically refresh in 5 secods' })
                  setTimeout(function() {
                      window.location.reload()
                  }, 5000)
              }

              setTimeout(app.checkForUpdate, 1000 * 60 * 30)
          },
      })
  }
  app.checkForUpdate()

  // Allow us to set a global base url for the API
  var oldSync = Backbone.sync;
  Backbone.sync = function(method, model, options) {
    var url = _.isFunction(model.url) ? model.url() : model.url;

    options = options || {};
    if (url) options.url = app.apiurl+url

    return oldSync.call(this, method, model, options);
  }

  // Pass prop to Backbone.ajax
  var oldAjax = Backbone.ajax
  Backbone.ajax = function(options) {
      var prop = app.prop

      // FormData
      if (options.data instanceof FormData) {
          options.data.append('prop', prop)

      // JSON content
      } else if (options.contentType == 'application/json' || options.type == 'DELETE') {
          if (options.data) var tmp = JSON.parse(options.data)
          else var tmp = {}

          if (Array.isArray(tmp)) tmp[0].prop = prop
          else {
            if (!tmp.prop) tmp.prop = prop
          }
          options.data = JSON.stringify(tmp)

      // Append to object for anything else
      } else {
          if (!options.data) options.data = {}
          if (!options.data.prop) options.data.prop = prop
      }

      // Send token with requst
      if (app.token) {
          options.beforeSend = function(request){
              request.setRequestHeader('Authorization', 'Bearer ' + app.token);
          }
      }

      return oldAjax.call(this, options)
  }

  // Override so we can redirect to login when theres no token present
  Backbone.Router.prototype.execute = function(callback, args, name) {
      if (!app.token) {
        app.login()
        return false
      }

      if (callback) callback.apply(this, args)
  }

  app.addRegions({
    content: '#container',
    header: '#header',
    sidebar: '#sidebar',
    dialog: DialogRegion,
    motd: '#motd',
  })

  /*
   Monitor all ajax requests to detect when user needs to login and/or
   is disconnected from the interwebs
  */
  $(document).ajaxError(_.debounce(function(event, xhr, settings, error) {
    console.log('ajax error', 'status', xhr.status, 'code', settings, error)

    var json;
    if (xhr.responseText) {
        try {
            json = $.parseJSON(xhr.responseText)
        } catch(err) {

        }
    }
    var msg = json && (json.error || json.msg) ? (json.error ? json.error : json.msg) : error

    if (xhr.readyState == 0) {
        app.alert({ message: 'A network request failed', persist: 'network' })

    }

    if (xhr.status == 401) app.login(xhr)
    if (xhr.status == 500) app.alert({ message: 'An application error has occured
'+msg+'
', persist: 'e500' })
    if (xhr.status == 503) {
        if (json) app.alert({ message: 'A database error has occured
'+msg+'
', persist: 'e503' })
        else  app.alert({ message: 'A server error has occured
'+msg+'
', persist: 'e503' })
    }
  }, 300))

  app.login = function(xhr) {
      app.bc.reset([{ title: 'Login' }])
      app.content.show(new LoginView())
  }

  /*
    Load module routers and startup application
  */
  app.addInitializer(function(options){
    require([
        'modules/dc/router',
        'modules/proposal/router',
        'modules/shipment/router',
        'modules/samples/router',
        'modules/projects/router',
        'modules/calendar/router',
        'modules/contact/router',
        'modules/cell/router',
        'modules/assign/router',
        'modules/fault/router',
        'modules/stats/router',
        'modules/blstats/router',
        'modules/status/router',
        'modules/docs/router',
        'modules/feedback/router',
        'modules/mc/router',
        'modules/admin/router',
        'modules/imaging/router',
        'modules/types/em/scipion/router',
    ], function() {

        this.sidebarview = new SideBarView()
        app.sidebar.show(this.sidebarview)

        // Breadcrumbs collection
        if (!app.bc) {
          app.bc = new Backbone.Collection()
          if (!this.headerview) this.headerview = new HeaderView({ bc: app.bc })
          app.header.show(this.headerview)
        }

        $.when(app.loadopts()).done(function() {
          if (app.token) app.getuser({
            callback: function() {
                if (!Backbone.History.started) app.starthistory()
            }
          })
          else {
            if (!Backbone.History.started) app.starthistory()
          }
        })
    })
  })

  /*
   Get the fedid for the logged in user to read cookie
  */
  app.getuser = function(options) {
    Backbone.ajax({
      url: app.apiurl+'/users/current',
      success: function(resp) {
          app.user = resp.user
          app.personid = resp.personid
          app.givenname = resp.givenname
          app.staff = resp.is_staff
          // Saving the default type for this user.
          // Needed for resetting the home view
          app.defaultType = resp.ty
          if (!app.type) app.type = resp.ty

          // Should put this somewhere else...
          app.user_can = function(perm) {
            return resp.permissions.indexOf(perm) > -1
          }

          app.cookie(null, function() {
            if (options && options.callback) options.callback()
          })
      },

      error: function() {
          if (options && options.callback) options.callback()
      }

    })
  }

  /*
   Shortcut to navigate
  */
  app.navigate = function(route,  options){
    options || (options = {});
    Backbone.history.navigate(route, options);
    log()
  }

  /*
   Cookie the selected proposal
      rename me app.get_proposal()
  */
  app.cookie = function(prop, callback) {
    if (prop) sessionStorage.setItem('prop', prop)
    else prop = sessionStorage.getItem('prop')

    app.prop = prop

    if (prop) {
        var proposal = new Proposal({ PROPOSAL: prop })
        proposal.fetch({
            success: function() {
                app.type = proposal.get('TYPE'),
                require(['modules/types/'+proposal.get('TYPE')+'/menu'], function(menus) {
                    proposal.set('MENUS', menus)
                    app.prop = prop
                    app.proposal = proposal
                    app.trigger('proposal:change', proposal)
                    if (callback) callback()
                })
            },

            error: function() {
                app.message({ title: 'No such proposal', message: 'The selected proposal does not exist' })
                app.prop = null
                sessionStorage.removeItem('prop')
            },

        })
    } else if (callback) callback()
  },

  /*
   Deselect the selected proposal.
   Used when navigating back to home page.
  */
  app.clearProposal = function() {
      // Clear the proposal cookie/object
    sessionStorage.removeItem('prop')

    delete app.prop
    // Reset type to the default for this user
    app.type = app.defaultType
    if (!app.type) {
      console.log('Error clearing proposal, no default type for this user')
    }

    // Recall the user info so we can set the default type for this person
    // app.getuser()
    // Now we need to tell any listening views that the proposal has changed...
    app.triggerMethod('proposal:change', null)
  },

  /*
   Load client side options and show MOTD
  */
  app.loadopts = function() {
      app.options = new Options()
      return app.options.fetch({
          data: { t: new Date().getTime() },
          success: function() {
              if (app.options.get('motd')) {
                  var options = {
                      persist: 'motd',
                      dismissible: true,
                      notify: true,
                      message: app.options.get('motd')
                  }
                  app.motd.show(new utils.alert(options))
              }
          }
      })
  }

  /*
   Log message to console
  */
  app.log = function() {
    console.log.apply(console, arguments)
  },

  /*
    Show an alert message at the top of the page and highlight
  */
  app.alert = function(options) {
      if (options && options.persist) {
          app.content.$el.find('.content .'+options.persist).remove()
      }

      app.content.$el.find('.content').prepend(new utils.alert(options).render().$el)
  }

  /*
   Show the generic message page (for errors, etc)
  */
  app.message = function(options) {
    app.content.show(new utils.generic_msg(options))
  }

  /*
   Check screen width
  */
  app.mobile = function() {
    return $(window).width() <= 600
  }

  /*
   Show blank loading view
  */
  app.loading = function() {
    var LoadingView = Marionette.ItemView.extend({ className: 'loading-container', template: '

' })
    app.content.show(new LoadingView())
  }

  /*
   Single Event for window scrolling
  */
  $(window).scroll(_.debounce(function() {
    app.trigger('window:scroll')
  }, 10))

  app.starthistory = function() {
      if(Backbone.history){
          Backbone.history.start({ pushState: true, root: app.appurl });

          // Only need this for pushState enabled browsers
          if (Backbone.history && Backbone.history._hasPushState) {
              var $document = $(window.document);
              var openLinkInTab = false;

              var is_relative_to_page = function(href) {
                  return href.match(/^\/|(http:|https:|ftp:|mailto:|javascript:)/) === null;
              };

              var is_routable = function(href) {
                  console.log('routable', href.indexOf('/'))
                  return href.indexOf("#") === -1 && (is_relative_to_page(href) || href.indexOf(Backbone.history.root) == 0 || href.indexOf('/') == 0) && (href.indexOf(app.apiurl) != 0);
              };

              $document.keydown(function(e) {
                  if (e.ctrlKey || e.keyCode === 91) {
                      openLinkInTab = true;
                  }
              });

              $document.keyup(function(e) {
                  openLinkInTab = false;
              });

              $document.on("click", "a", function(e) {
                  var href =  $(this).attr("href");
                  if (!href) return
                  if (is_routable(href)) {
                      e.preventDefault();
                      Backbone.history.navigate(href, true);
                  }
              });
          }

          Backbone.history.on('route', function(route, params) {
              console.log('routing', arguments)
              log()
          })
      }
  }

  function log() {
      var data = { location: window.location.pathname }
      Backbone.ajax({
          url: app.apiurl+'/users/log/',
          type: 'POST',
          data: data
      })
  }

  // log()

  return app

})
<commit_msg>Fix issue loading shipping, needs app.Options object created earlier<commit_after>/*
    Copyright 2015 Diamond Light Source <stuart.fisher@diamond.ac.uk>

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

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

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

define(['backbone', 'marionette', 'underscore', 'jquery',

    'views/header',
    'views/sidebar',
    'views/dialogregion',
    'views/login',

    'models/proposal',
    'models/options',

    'utils',
    'config.json',
    'jquery.cookie', 'jquery-ui',
        ],
function(Backbone, Marionette, _, $, HeaderView, SideBarView, DialogRegion, LoginView, Proposal, Options, utils, config) {

  window.app = new Marionette.Application()

  console.log('CONFIG', config)

  // Moved to here so its available on app start
  app.options = new Options()

  // Base url for the api
  app.apiurl = config.apiurl

  // Base url for the app
  app.appurl = config.appurl

  // reference to config
  app.config = config

  // Restore token if its in sessionStorage
  app.token = sessionStorage.getItem('token')

  // Allow the app to load a proposal on bootstrap
  app.parseQuery = function() {
      var str = location.search.replace(/\?/, '').split(/&/)
      var pairs = {}
      _.each(str, function(v) {
          var kv = v.split(/=/)
          pairs[kv[0]] = kv[1]
      })

      console.log('pairs', pairs)

      if ('prop' in pairs) sessionStorage.setItem('prop', pairs.prop)
  }

  app.parseQuery()

  // Allow the app to autoupdate itself when running
  app.checkForUpdate = function() {
      Backbone.ajax({
          url: app.appurl+'/js/config.json?t='+(new Date().getTime()),
          success: function(config) {
              console.log('old', app.config.build, 'new', config.build)
              if (config.build != app.config.build) {
                  app.alert({ message: 'An update to SynchWeb is available. This page will automatically refresh in 5 secods' })
                  setTimeout(function() {
                      window.location.reload()
                  }, 5000)
              }

              setTimeout(app.checkForUpdate, 1000 * 60 * 30)
          },
      })
  }
  app.checkForUpdate()

  // Allow us to set a global base url for the API
  var oldSync = Backbone.sync;
  Backbone.sync = function(method, model, options) {
    var url = _.isFunction(model.url) ? model.url() : model.url;

    options = options || {};
    if (url) options.url = app.apiurl+url

    return oldSync.call(this, method, model, options);
  }

  // Pass prop to Backbone.ajax
  var oldAjax = Backbone.ajax
  Backbone.ajax = function(options) {
      var prop = app.prop

      // FormData
      if (options.data instanceof FormData) {
          options.data.append('prop', prop)

      // JSON content
      } else if (options.contentType == 'application/json' || options.type == 'DELETE') {
          if (options.data) var tmp = JSON.parse(options.data)
          else var tmp = {}

          if (Array.isArray(tmp)) tmp[0].prop = prop
          else {
            if (!tmp.prop) tmp.prop = prop
          }
          options.data = JSON.stringify(tmp)

      // Append to object for anything else
      } else {
          if (!options.data) options.data = {}
          if (!options.data.prop) options.data.prop = prop
      }

      // Send token with requst
      if (app.token) {
          options.beforeSend = function(request){
              request.setRequestHeader('Authorization', 'Bearer ' + app.token);
          }
      }

      return oldAjax.call(this, options)
  }

  // Override so we can redirect to login when theres no token present
  Backbone.Router.prototype.execute = function(callback, args, name) {
      if (!app.token) {
        app.login()
        return false
      }

      if (callback) callback.apply(this, args)
  }

  app.addRegions({
    content: '#container',
    header: '#header',
    sidebar: '#sidebar',
    dialog: DialogRegion,
    motd: '#motd',
  })

  /*
   Monitor all ajax requests to detect when user needs to login and/or
   is disconnected from the interwebs
  */
  $(document).ajaxError(_.debounce(function(event, xhr, settings, error) {
    console.log('ajax error', 'status', xhr.status, 'code', settings, error)

    var json;
    if (xhr.responseText) {
        try {
            json = $.parseJSON(xhr.responseText)
        } catch(err) {

        }
    }
    var msg = json && (json.error || json.msg) ? (json.error ? json.error : json.msg) : error

    if (xhr.readyState == 0) {
        app.alert({ message: 'A network request failed', persist: 'network' })

    }

    if (xhr.status == 401) app.login(xhr)
    if (xhr.status == 500) app.alert({ message: 'An application error has occured
'+msg+'
', persist: 'e500' })
    if (xhr.status == 503) {
        if (json) app.alert({ message: 'A database error has occured
'+msg+'
', persist: 'e503' })
        else  app.alert({ message: 'A server error has occured
'+msg+'
', persist: 'e503' })
    }
  }, 300))

  app.login = function(xhr) {
      app.bc.reset([{ title: 'Login' }])
      app.content.show(new LoginView())
  }

  /*
    Load module routers and startup application
  */
  app.addInitializer(function(options){
    require([
        'modules/dc/router',
        'modules/proposal/router',
        'modules/shipment/router',
        'modules/samples/router',
        'modules/projects/router',
        'modules/calendar/router',
        'modules/contact/router',
        'modules/cell/router',
        'modules/assign/router',
        'modules/fault/router',
        'modules/stats/router',
        'modules/blstats/router',
        'modules/status/router',
        'modules/docs/router',
        'modules/feedback/router',
        'modules/mc/router',
        'modules/admin/router',
        'modules/imaging/router',
        'modules/types/em/scipion/router',
    ], function() {

        this.sidebarview = new SideBarView()
        app.sidebar.show(this.sidebarview)

        // Breadcrumbs collection
        if (!app.bc) {
          app.bc = new Backbone.Collection()
          if (!this.headerview) this.headerview = new HeaderView({ bc: app.bc })
          app.header.show(this.headerview)
        }

        $.when(app.loadopts()).done(function() {
          if (app.token) app.getuser({
            callback: function() {
                if (!Backbone.History.started) app.starthistory()
            }
          })
          else {
            if (!Backbone.History.started) app.starthistory()
          }
        })
    })
  })

  /*
   Get the fedid for the logged in user to read cookie
  */
  app.getuser = function(options) {
    Backbone.ajax({
      url: app.apiurl+'/users/current',
      success: function(resp) {
          app.user = resp.user
          app.personid = resp.personid
          app.givenname = resp.givenname
          app.staff = resp.is_staff
          // Saving the default type for this user.
          // Needed for resetting the home view
          app.defaultType = resp.ty
          if (!app.type) app.type = resp.ty

          // Should put this somewhere else...
          app.user_can = function(perm) {
            return resp.permissions.indexOf(perm) > -1
          }

          app.cookie(null, function() {
            if (options && options.callback) options.callback()
          })
      },

      error: function() {
          if (options && options.callback) options.callback()
      }

    })
  }

  /*
   Shortcut to navigate
  */
  app.navigate = function(route,  options){
    options || (options = {});
    Backbone.history.navigate(route, options);
    log()
  }

  /*
   Cookie the selected proposal
      rename me app.get_proposal()
  */
  app.cookie = function(prop, callback) {
    if (prop) sessionStorage.setItem('prop', prop)
    else prop = sessionStorage.getItem('prop')

    app.prop = prop

    if (prop) {
        var proposal = new Proposal({ PROPOSAL: prop })
        proposal.fetch({
            success: function() {
                app.type = proposal.get('TYPE'),
                require(['modules/types/'+proposal.get('TYPE')+'/menu'], function(menus) {
                    proposal.set('MENUS', menus)
                    app.prop = prop
                    app.proposal = proposal
                    app.trigger('proposal:change', proposal)
                    if (callback) callback()
                })
            },

            error: function() {
                app.message({ title: 'No such proposal', message: 'The selected proposal does not exist' })
                app.prop = null
                sessionStorage.removeItem('prop')
            },

        })
    } else if (callback) callback()
  },

  /*
   Deselect the selected proposal.
   Used when navigating back to home page.
  */
  app.clearProposal = function() {
      // Clear the proposal cookie/object
    sessionStorage.removeItem('prop')

    delete app.prop
    // Reset type to the default for this user
    app.type = app.defaultType
    if (!app.type) {
      console.log('Error clearing proposal, no default type for this user')
    }

    // Recall the user info so we can set the default type for this person
    // app.getuser()
    // Now we need to tell any listening views that the proposal has changed...
    app.triggerMethod('proposal:change', null)
  },

  /*
   Load client side options and show MOTD
  */
  app.loadopts = function() {
    //   app.options = new Options()
      return app.options.fetch({
          data: { t: new Date().getTime() },
          success: function() {
              if (app.options.get('motd')) {
                  var options = {
                      persist: 'motd',
                      dismissible: true,
                      notify: true,
                      message: app.options.get('motd')
                  }
                  app.motd.show(new utils.alert(options))
              }
          }
      })
  }

  /*
   Log message to console
  */
  app.log = function() {
    console.log.apply(console, arguments)
  },

  /*
    Show an alert message at the top of the page and highlight
  */
  app.alert = function(options) {
      if (options && options.persist) {
          app.content.$el.find('.content .'+options.persist).remove()
      }

      app.content.$el.find('.content').prepend(new utils.alert(options).render().$el)
  }

  /*
   Show the generic message page (for errors, etc)
  */
  app.message = function(options) {
    app.content.show(new utils.generic_msg(options))
  }

  /*
   Check screen width
  */
  app.mobile = function() {
    return $(window).width() <= 600
  }

  /*
   Show blank loading view
  */
  app.loading = function() {
    var LoadingView = Marionette.ItemView.extend({ className: 'loading-container', template: '

' })
    app.content.show(new LoadingView())
  }

  /*
   Single Event for window scrolling
  */
  $(window).scroll(_.debounce(function() {
    app.trigger('window:scroll')
  }, 10))

  app.starthistory = function() {
      if(Backbone.history){
          Backbone.history.start({ pushState: true, root: app.appurl });

          // Only need this for pushState enabled browsers
          if (Backbone.history && Backbone.history._hasPushState) {
              var $document = $(window.document);
              var openLinkInTab = false;

              var is_relative_to_page = function(href) {
                  return href.match(/^\/|(http:|https:|ftp:|mailto:|javascript:)/) === null;
              };

              var is_routable = function(href) {
                  console.log('routable', href.indexOf('/'))
                  return href.indexOf("#") === -1 && (is_relative_to_page(href) || href.indexOf(Backbone.history.root) == 0 || href.indexOf('/') == 0) && (href.indexOf(app.apiurl) != 0);
              };

              $document.keydown(function(e) {
                  if (e.ctrlKey || e.keyCode === 91) {
                      openLinkInTab = true;
                  }
              });

              $document.keyup(function(e) {
                  openLinkInTab = false;
              });

              $document.on("click", "a", function(e) {
                  var href =  $(this).attr("href");
                  if (!href) return
                  if (is_routable(href)) {
                      e.preventDefault();
                      Backbone.history.navigate(href, true);
                  }
              });
          }

          Backbone.history.on('route', function(route, params) {
              console.log('routing', arguments)
              log()
          })
      }
  }

  function log() {
      var data = { location: window.location.pathname }
      Backbone.ajax({
          url: app.apiurl+'/users/log/',
          type: 'POST',
          data: data
      })
  }

  // log()

  return app

})
<|endoftext|>


<commit_before>// app/routes/release.js

var https = require('https');
var config = require('nconf');

module.exports = function(router) {
  'use strict';

  // This will handle the url calls for /ping
  router.route('/')
  .get(function(req, res) {
    var releaseURLs = {};
    var os = req.param('os');
    var project = req.param('project');

    console.log("[Request] Looking for OS: " + os + " project: " + project);

    var buildResponse = function(releases) {
      var releaseURL = "https://github.com/Storj/" + project + "/releases/latest";

      if (releases) {
        releases.forEach(function(release) {
          if (release.name.match('win32')) {
            releaseURLs['win32'] = release.browser_download_url;
            //releaseURLs['win32'] =
          };
          if (release.name.match('osx64')) {
            releaseURLs['osx64'] = release.browser_download_url;
          };
          if (release.name.match('amd64')) {
            releaseURLs['amd64'] = release.browser_download_url;
          };
        });

        if (os) {
          releaseURL = releaseURLs[os] || releaseURL;
        }
      }

      sendResponse(releaseURL);
    }

    var sendResponse = function(assetURL) {
      var responseJSON = {
        "url": assetURL
      }
      console.log("[sendResponse] Sending response: " + assetURL);
      res.send(assetURL);
    };

    var apiToken = config.get('GITHUB_API_TOKEN');

    var requestOptions = {
      host: "api.github.com",
      path: '/repos/Storj/' + project + '/releases/latest',
      method: "GET",
      headers: {
        'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36',
        'Authorization': 'token ' + apiToken
      }
    }

    if (os && project) {
      var request = https.request(requestOptions, function(resp) {
        var data = "";
        resp.setEncoding('utf8');
        resp.on('data', function (chunk) {
          data += chunk;
        });

        resp.on('end', function () {
          var responseCode = resp.statusCode;

          if (responseCode == 401) {
            var errorMessage = JSON.parse(data).message;

            console.log("[ERROR](" + responseCode + ") " + errorMessage);

            return res.send("[ERROR](" + responseCode + ") " + errorMessage);
          }

          var releases = JSON.parse(data).assets;

          buildResponse(releases);
        });
      });

      request.end();
    } else {
      res.send("Please provide valid os and project");
    }
  });
};

<commit_msg>Output to json<commit_after>// app/routes/release.js

var https = require('https');
var config = require('nconf');

module.exports = function(router) {
  'use strict';

  // This will handle the url calls for /ping
  router.route('/')
  .get(function(req, res) {
    var releaseURLs = {};
    var os = req.param('os');
    var project = req.param('project');

    console.log("[Request] Looking for OS: " + os + " project: " + project);

    var buildResponse = function(releases) {
      var releaseURL = "https://github.com/Storj/" + project + "/releases/latest";

      if (releases) {
        releases.forEach(function(release) {
          if (release.name.match('win32')) {
            releaseURLs['win32'] = release.browser_download_url;
            //releaseURLs['win32'] =
          };
          if (release.name.match('osx64')) {
            releaseURLs['osx64'] = release.browser_download_url;
          };
          if (release.name.match('amd64')) {
            releaseURLs['amd64'] = release.browser_download_url;
          };
        });

        if (os) {
          releaseURL = releaseURLs[os] || releaseURL;
        }
      }

      sendResponse(releaseURL);
    }

    var sendResponse = function(assetURL) {
      var responseJSON = {
        "url": assetURL
      }
      console.log("[sendResponse] Sending response: " + assetURL);
      res.send(responseJSON);
    };

    var apiToken = config.get('GITHUB_API_TOKEN');

    var requestOptions = {
      host: "api.github.com",
      path: '/repos/Storj/' + project + '/releases/latest',
      method: "GET",
      headers: {
        'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36',
        'Authorization': 'token ' + apiToken
      }
    }

    if (os && project) {
      var request = https.request(requestOptions, function(resp) {
        var data = "";
        resp.setEncoding('utf8');
        resp.on('data', function (chunk) {
          data += chunk;
        });

        resp.on('end', function () {
          var responseCode = resp.statusCode;

          if (responseCode == 401) {
            var errorMessage = JSON.parse(data).message;

            console.log("[ERROR](" + responseCode + ") " + errorMessage);

            return res.send("[ERROR](" + responseCode + ") " + errorMessage);
          }

          var releases = JSON.parse(data).assets;

          buildResponse(releases);
        });
      });

      request.end();
    } else {
      res.send("Please provide valid os and project");
    }
  });
};

<|endoftext|>