<commit_before>'use strict';

var winners = [{userName:'Sara', score: 19}, {userName:'Bob', score:53}];
var highScoreList = [];
//score constructor
function NewScore(userName, score) {
  this.userName = userName;
  this.score = score;
  highScoreList.push(this);
}
//function sorts the high scores
if (localStorage.highScoreList) {
  highScoreList = JSON.parse(localStorage.highScoreList);
}
new NewScore(winners[winners.length - 1].userName, winners[winners.length - 1].score);
highScoreList.sort(function(a,b) {
  return b.score - a.score;
});
//creates the high score table
for (var i = 0; i < highScoreList.length; i++) {
  var table = document.getElementById('hiScoreTable');
  var tr = document.createElement('tr');
  var rank = document.createElement('td');
  rank.innerText = i + 1;
  tr.appendChild(rank);
  var userName = document.createElement('td');
  userName.innerText = highScoreList[i].userName;
  tr.appendChild(userName);
  var score = document.createElement('td');
  score.innerText = highScoreList[i].score;
  tr.appendChild(score);
  table.appendChild(tr);
};
if (highScoreList.length >= 10) {
  highScoreList.pop();
};
var highScoreData = JSON.stringify(highScoreList);
localStorage.highScoreList = highScoreData;

//
var test1 = new NewScore('bob', 23);
var test2 = new NewScore('Al', 2);
var test3 = new NewScore('Jane', 45);
var test4 = new NewScore('Sara', 5);
var test5 = new NewScore('Vince', 15);
// [i].score

// X create an object that is the score & userName
//     ordered list = no need for position number (automatic)
//
// store obj in array (in localStorage)
//
// sort the array by score value
//
// if array has more than 10, pop last item
//store in local storage
<commit_msg>minor cleanup adjustments<commit_after>'use strict';

var highScoreList = [];
//score constructor
function NewScore(userName, score) {
  this.userName = userName;
  this.score = score;
  highScoreList.push(this);
}
//function sorts the high scores
if (localStorage.highScoreList) {
  highScoreList = JSON.parse(localStorage.highScoreList);
}
new NewScore(winners[winners.length - 1].userName, winners[winners.length - 1].score);
highScoreList.sort(function(a,b) {
  return b.score - a.score;
});
//creates the high score table
for (var i = 0; i < highScoreList.length; i++) {
  var table = document.getElementById('hiScoreTable');
  var tr = document.createElement('tr');
  var rank = document.createElement('td');
  rank.innerText = i + 1;
  tr.appendChild(rank);
  var userName = document.createElement('td');
  userName.innerText = highScoreList[i].userName;
  tr.appendChild(userName);
  var score = document.createElement('td');
  score.innerText = highScoreList[i].score;
  tr.appendChild(score);
  table.appendChild(tr);
};
if (highScoreList.length >= 10) {
  highScoreList.pop();
};
var highScoreData = JSON.stringify(highScoreList);
localStorage.highScoreList = highScoreData;

//
var test1 = new NewScore('bob', 23);
var test2 = new NewScore('Al', 2);
var test3 = new NewScore('Jane', 45);
var test4 = new NewScore('Sara', 5);
var test5 = new NewScore('Vince', 15);
// [i].score

// X create an object that is the score & userName
//     ordered list = no need for position number (automatic)
//
// store obj in array (in localStorage)
//
// sort the array by score value
//
// if array has more than 10, pop last item
//store in local storage
<|endoftext|>


<commit_before>import TransitiveOverlay from '@opentripplanner/transitive-overlay'
import React, { Component } from 'react'
import { connect } from 'react-redux'

import { getTransitiveData } from '../../util/state'

/**
 * Wrapper for TransitiveOverlay that avoids rerenders by checking transitive
 * data computed from redux store.
 */
class TransitiveCanvasOverlay extends Component {
  shouldComponentUpdate (nextProps) {
    return nextProps.transitiveData !== this.props.transitiveData
  }

  render () {
    const { labeledModes, styles, transitiveData } = this.props
    return (
      <TransitiveOverlay
        labeledModes={labeledModes}
        styles={styles}
        transitiveData={transitiveData}
      />
    )
  }
}

// connect to the redux store

const mapStateToProps = (state, ownProps) => {
  const { labeledModes, styles } = state.otp.config.map.transitive || {}

  return {
    labeledModes,
    styles,
    transitiveData: getTransitiveData(state, ownProps)
  }
}

export default connect(mapStateToProps)(TransitiveCanvasOverlay)
<commit_msg>refactor(transitive-overlay): Remove componentShouldUpdate<commit_after>import TransitiveCanvasOverlay from '@opentripplanner/transitive-overlay'
import { connect } from 'react-redux'

import { getTransitiveData } from '../../util/state'

// connect to the redux store

const mapStateToProps = (state, ownProps) => {
  const { labeledModes, styles } = state.otp.config.map.transitive || {}
  return {
    labeledModes,
    styles,
    transitiveData: getTransitiveData(state, ownProps)
  }
}

export default connect(mapStateToProps)(TransitiveCanvasOverlay)
<|endoftext|>


<commit_before>L.AwesomeMarkers.Icon.prototype.options.prefix = 'ion'

document.addEventListener('DOMContentLoaded', main)

function get(url) {
  return new Promise(function(resolve, reject) {
    var req = new XMLHttpRequest();
    req.open('GET', url);

    req.onload = function() {
      if (req.status == 200) {
        resolve(req.response);
      }
      else {
        reject(Error(req.statusText));
      }
    };

    req.onerror = function() {
      reject(Error("Network Error"));
    };

    req.send();
  });
}

function getJSON(url) {
  return get(url).then(JSON.parse)
}

function main() {
  getJSON("config.json").then( function (config) {
    moment.locale("de")

    var options = { worldCopyJump: true,
                    zoomControl: false
                  }

    var map = L.map(document.getElementById("map"), options)

    var sh = document.getElementById("sidebarhandle")
    sh.onclick = function () {
      var sb = document.getElementById("sidebar")

      if (sb.classList.contains("hidden"))
        sb.classList.remove("hidden")
      else
        sb.classList.add("hidden")
    }

    var urls = [ config.dataPath + 'nodes.json',
                 config.dataPath + 'graph.json'
               ]

    var p = Promise.all(urls.map(getJSON))
    p.then(handle_data(config, map))
  })
}

function sort(key, d) {
  return d.slice().sort( function (a, b) {
    return a[key] - b[key]
  }).reverse()
}

function limit(key, m, d) {
  return d.filter( function (d) {
    return d[key].isAfter(m)
  })
}

function offline(d) {
  return !d.flags.online
}

function online(d) {
  return d.flags.online
}

function has_location(d) {
  return "location" in d.nodeinfo
}

function subtract(a, b) {
  var ids = {}

  b.forEach( function (d) {
    ids[d.nodeinfo.node_id] = true
  })

  return a.filter( function (d) {
    return !(d.nodeinfo.node_id in ids)
  })
}

function handle_data(config, map) {
  return function (data) {
    var nodedict = data[0]
    var nodes = Object.keys(nodedict.nodes).map(function (key) { return nodedict.nodes[key] })

    nodes = nodes.filter( function (d) {
      return "firstseen" in d && "lastseen" in d
    })

    nodes.forEach( function(node) {
      node.firstseen = moment.utc(node.firstseen)
      node.lastseen = moment.utc(node.lastseen)
    })

    var age = moment().subtract(14, 'days')

    var newnodes = limit("firstseen", age, sort("firstseen", nodes).filter(online))
    var lostnodes = limit("lastseen", age, sort("lastseen", nodes).filter(offline))

    var onlinenodes = subtract(nodes.filter(online).filter(has_location), newnodes)

    var graph = data[1].batadv
    var graphnodes = data[0].nodes

    graph.nodes.forEach( function (d) {
      if (d.node_id in graphnodes && "location" in graphnodes[d.node_id].nodeinfo)
        d.node = graphnodes[d.node_id]
    })

    graph.links.forEach( function (d) {
      if (graph.nodes[d.source].node)
        d.source = graph.nodes[d.source]
      else
        d.source = undefined

      if (graph.nodes[d.target].node)
        d.target = graph.nodes[d.target]
      else
        d.target = undefined
    })

    graph = graph.links.filter( function (d) {
      var ok = d.source !== undefined && d.target !== undefined
      return ok
    })

    graph.forEach( function (d) {
      d.latlngs = []
      d.latlngs.push(L.latLng(d.source.node.nodeinfo.location.latitude, d.source.node.nodeinfo.location.longitude))
      d.latlngs.push(L.latLng(d.target.node.nodeinfo.location.latitude, d.target.node.nodeinfo.location.longitude))

      d.distance = d.latlngs[0].distanceTo(d.latlngs[1])
    })

    longlinks = graph.slice().sort( function (a, b) {
      return a.distance - b.distance
    }).reverse().slice(0, Math.ceil(config.longLinkPercentile * graph.length))

    var markers = mkmap(map, newnodes, lostnodes, onlinenodes, graph, showNodeinfo, showLinkinfo)

    var gotoAnything = gotoBuilder(markers, showNodeinfo, showLinkinfo)

    addToList(document.getElementById("newnodes"), config.showContact, "firstseen", gotoAnything.node, newnodes)
    addToList(document.getElementById("lostnodes"), config.showContact, "lastseen", gotoAnything.node, lostnodes)
    addToLongLinksList(document.getElementById("longlinks"), gotoAnything.link, longlinks)

    showMeshstats(document.getElementById("meshstats"), nodes)
  }
}

function showDistance(d) {
  return (new Intl.NumberFormat("de-DE", {maximumFractionDigits: 0}).format(d.distance)) + " m"
}

function showTq(d) {
  var opts = { maximumFractionDigits: 2,
               minimumFractionDigits: 2
             }

  return (new Intl.NumberFormat("de-DE", opts).format(d.tq)) + " TQ"
}

function linkId(d) {
  return d.source.node.nodeinfo.node_id + "-" + d.target.node.nodeinfo.node_id
}

function mkmap(map, newnodes, lostnodes, onlinenodes, graph, showNodeinfo, showLinkinfo) {
  L.control.zoom({ position: "topright" }).addTo(map)

  L.tileLayer("http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg", {
    subdomains: "1234",
    type: "osm",
    attribution: "Map data Tiles © MapQuest , Map data © OpenStreetMap contributors, CC-BY-SA",
    maxZoom: 18
  }).addTo(map)

  var markersDict = addLinksToMap(map, graph, showLinkinfo)

  var nodes = newnodes.concat(lostnodes).filter( function (d) {
    return "location" in d.nodeinfo
  })

  var markers = nodes.map( function (d) {
    var icon = L.AwesomeMarkers.icon({ markerColor: d.flags.online ? "green" : "red",
                                       icon: d.flags.online ? "lightbulb" : "bug" })

    var opt = { icon: icon,
                title: d.nodeinfo.hostname
              }

    var m = L.marker([d.nodeinfo.location.latitude, d.nodeinfo.location.longitude], opt)

    m.on('click', function () { return showNodeinfo(d) })
    m.bindPopup(d.nodeinfo.hostname)

    markersDict[d.nodeinfo.node_id] = m

    return m
  })

  var onlinemarkers = onlinenodes.map( function (d) {
    var opt = { color: "#76B22D",
                fillColor: "#76B22D",
                radius: 5,
                opacity: 0.7,
                fillOpacity: 0.5
              }

    var m = L.circleMarker([d.nodeinfo.location.latitude, d.nodeinfo.location.longitude], opt)

    m.on('click', function () { return showNodeinfo(d) })
    m.bindPopup(d.nodeinfo.hostname)

    markersDict[d.nodeinfo.node_id] = m

    return m
  })

  var group = L.featureGroup(markers).addTo(map)
  var group_online = L.featureGroup(onlinemarkers).addTo(map)

  map.fitBounds(group.getBounds(), {paddingTopLeft: [getSidebarWidth(), 0]})

  var funcDict = {}

  Object.keys(markersDict).map( function(k) {
       funcDict[k] = function (d) {
         var m = markersDict[k]
         var bounds
         if ("getBounds" in m) {
           bounds = m.getBounds()
         } else {
           bounds = L.latLngBounds([m.getLatLng()])
         }

         map.fitBounds(bounds, {paddingTopLeft: [getSidebarWidth(), 0]})
         m.openPopup(bounds.getCenter())
       }
  });

  return funcDict
}

function getSidebarWidth() {
  var small = window.matchMedia("(max-width: 60em)");
  var sb = document.getElementById("sidebar")
  return small.matches ? 0 : sb.offsetWidth
}

function addLinksToMap(map, graph, showLinkinfo) {
  var markersDict = {}

  var scale = chroma.scale(['green', 'orange', 'red']).domain([1, 10])

  var lines = graph.map( function (d) {
    var opts = { color: scale(d.tq).hex(),
                 weight: 4
               }

    var line = L.polyline(d.latlngs, opts)

    line.bindPopup(d.source.node.nodeinfo.hostname + " – " + d.target.node.nodeinfo.hostname + "
" + showDistance(d) + " / " + showTq(d) + "")
    line.on('click', function () { return showLinkinfo(d) })

    markersDict[linkId(d)] = line

    return line
  })

  var group = L.featureGroup(lines).addTo(map)

  return markersDict
}

function addToLongLinksList(el, gotoProxy, links) {
  links.forEach( function (d) {
    var row = document.createElement("tr")
    var td1 = document.createElement("td")
    var a = document.createElement("a")
    a.textContent = d.source.node.nodeinfo.hostname + " – " + d.target.node.nodeinfo.hostname
    a.href = "#"
    a.onclick = gotoProxy(d)
    td1.appendChild(a)
    row.appendChild(td1)

    var td2 = document.createElement("td")
    td2.textContent = showTq(d)
    row.appendChild(td2)

    var td3 = document.createElement("td")
    td3.textContent = showDistance(d)
    row.appendChild(td3)

    el.appendChild(row)
  })
}

function addToList(el, showContact, tf, gotoProxy, list) {
  list.forEach( function (d) {
    var time = moment(d[tf]).fromNow()

    var row = document.createElement("tr")
    var td1 = document.createElement("td")
    var a = document.createElement("a")
    a.classList.add("hostname")
    a.classList.add(d.flags.online ? "online" : "offline")
    a.textContent = d.nodeinfo.hostname
    a.href = "#"
    a.onclick = gotoProxy(d)
    td1.appendChild(a)

    if ("location" in d.nodeinfo) {
      var span = document.createElement("span")
      span.classList.add("icon")
      span.classList.add("ion-location")
      td1.appendChild(span)
    }

    if ("owner" in d.nodeinfo && showContact) {
      var contact = d.nodeinfo.owner.contact
      td1.appendChild(document.createTextNode(" – " + contact + ""))
    }

    var td2 = document.createElement("td")
    td2.textContent = time

    row.appendChild(td1)
    row.appendChild(td2)
    el.appendChild(row)
  })
}

function sum(a) {
  return a.reduce( function (a, b) {
    return a + b
  }, 0)
}

function one() {
  return 1
}

function showMeshstats(el, nodes) {
  var totalNodes = sum(nodes.filter(online).map(one))

  var totalClients = sum(nodes.filter(online).map( function (d) {
    return d.statistics.clients
  }))

  var totalGateways = sum(nodes.filter(online).filter( function (d) {
    return d.flags.gateway
  }).map(one))

  el.textContent = totalNodes + " Knoten (online), " +
                   totalClients + " Clients, " +
                   totalGateways + " Gateways"
}

function showNodeinfo(d) {
  var el = document.getElementById("nodeinfo")

  destroy()
  el.classList.remove("hidden")
  el.scrollIntoView(false)

  var closeButton = document.createElement("button")
  closeButton.classList.add("close")
  closeButton.onclick = destroy
  el.appendChild(closeButton)

  var h2 = document.createElement("h2")
  h2.textContent = d.nodeinfo.hostname
  el.appendChild(h2)

  var pre = document.createElement("pre")
  pre.textContent = JSON.stringify(d, null, ' ')
  el.appendChild(pre)

  function destroy() {
    el.classList.add("hidden")
    while (el.hasChildNodes())
      el.removeChild(el.childNodes[0])
  }
}

function showLinkinfo(d) {
}

function gotoBuilder(markers, nodes, links) {
  function gotoNode(d) {
    if (d.nodeinfo.node_id in markers)
      markers[d.nodeinfo.node_id]()

    nodes(d)

    return false
  }

  function gotoLink(d) {
    if (linkId(d) in markers)
      markers[linkId(d)]()

    links(d)

    return false
  }

  return { node: function (d) { return function () { return gotoNode(d) }},
           link: function (d) { return function () { return gotoLink(d) }}
         }
}
<commit_msg>don't fail when newnodes and lostnodes are empty<commit_after>L.AwesomeMarkers.Icon.prototype.options.prefix = 'ion'

document.addEventListener('DOMContentLoaded', main)

function get(url) {
  return new Promise(function(resolve, reject) {
    var req = new XMLHttpRequest();
    req.open('GET', url);

    req.onload = function() {
      if (req.status == 200) {
        resolve(req.response);
      }
      else {
        reject(Error(req.statusText));
      }
    };

    req.onerror = function() {
      reject(Error("Network Error"));
    };

    req.send();
  });
}

function getJSON(url) {
  return get(url).then(JSON.parse)
}

function main() {
  getJSON("config.json").then( function (config) {
    moment.locale("de")

    var options = { worldCopyJump: true,
                    zoomControl: false
                  }

    var map = L.map(document.getElementById("map"), options)

    var sh = document.getElementById("sidebarhandle")
    sh.onclick = function () {
      var sb = document.getElementById("sidebar")

      if (sb.classList.contains("hidden"))
        sb.classList.remove("hidden")
      else
        sb.classList.add("hidden")
    }

    var urls = [ config.dataPath + 'nodes.json',
                 config.dataPath + 'graph.json'
               ]

    var p = Promise.all(urls.map(getJSON))
    p.then(handle_data(config, map))
  })
}

function sort(key, d) {
  return d.slice().sort( function (a, b) {
    return a[key] - b[key]
  }).reverse()
}

function limit(key, m, d) {
  return d.filter( function (d) {
    return d[key].isAfter(m)
  })
}

function offline(d) {
  return !d.flags.online
}

function online(d) {
  return d.flags.online
}

function has_location(d) {
  return "location" in d.nodeinfo
}

function subtract(a, b) {
  var ids = {}

  b.forEach( function (d) {
    ids[d.nodeinfo.node_id] = true
  })

  return a.filter( function (d) {
    return !(d.nodeinfo.node_id in ids)
  })
}

function handle_data(config, map) {
  return function (data) {
    var nodedict = data[0]
    var nodes = Object.keys(nodedict.nodes).map(function (key) { return nodedict.nodes[key] })

    nodes = nodes.filter( function (d) {
      return "firstseen" in d && "lastseen" in d
    })

    nodes.forEach( function(node) {
      node.firstseen = moment.utc(node.firstseen)
      node.lastseen = moment.utc(node.lastseen)
    })

    var age = moment().subtract(14, 'days')

    var newnodes = limit("firstseen", age, sort("firstseen", nodes).filter(online))
    var lostnodes = limit("lastseen", age, sort("lastseen", nodes).filter(offline))

    var onlinenodes = subtract(nodes.filter(online).filter(has_location), newnodes)

    var graph = data[1].batadv
    var graphnodes = data[0].nodes

    graph.nodes.forEach( function (d) {
      if (d.node_id in graphnodes && "location" in graphnodes[d.node_id].nodeinfo)
        d.node = graphnodes[d.node_id]
    })

    graph.links.forEach( function (d) {
      if (graph.nodes[d.source].node)
        d.source = graph.nodes[d.source]
      else
        d.source = undefined

      if (graph.nodes[d.target].node)
        d.target = graph.nodes[d.target]
      else
        d.target = undefined
    })

    graph = graph.links.filter( function (d) {
      var ok = d.source !== undefined && d.target !== undefined
      return ok
    })

    graph.forEach( function (d) {
      d.latlngs = []
      d.latlngs.push(L.latLng(d.source.node.nodeinfo.location.latitude, d.source.node.nodeinfo.location.longitude))
      d.latlngs.push(L.latLng(d.target.node.nodeinfo.location.latitude, d.target.node.nodeinfo.location.longitude))

      d.distance = d.latlngs[0].distanceTo(d.latlngs[1])
    })

    longlinks = graph.slice().sort( function (a, b) {
      return a.distance - b.distance
    }).reverse().slice(0, Math.ceil(config.longLinkPercentile * graph.length))

    var markers = mkmap(map, newnodes, lostnodes, onlinenodes, graph, showNodeinfo, showLinkinfo)

    var gotoAnything = gotoBuilder(markers, showNodeinfo, showLinkinfo)

    addToList(document.getElementById("newnodes"), config.showContact, "firstseen", gotoAnything.node, newnodes)
    addToList(document.getElementById("lostnodes"), config.showContact, "lastseen", gotoAnything.node, lostnodes)
    addToLongLinksList(document.getElementById("longlinks"), gotoAnything.link, longlinks)

    showMeshstats(document.getElementById("meshstats"), nodes)
  }
}

function showDistance(d) {
  return (new Intl.NumberFormat("de-DE", {maximumFractionDigits: 0}).format(d.distance)) + " m"
}

function showTq(d) {
  var opts = { maximumFractionDigits: 2,
               minimumFractionDigits: 2
             }

  return (new Intl.NumberFormat("de-DE", opts).format(d.tq)) + " TQ"
}

function linkId(d) {
  return d.source.node.nodeinfo.node_id + "-" + d.target.node.nodeinfo.node_id
}

function mkmap(map, newnodes, lostnodes, onlinenodes, graph, showNodeinfo, showLinkinfo) {
  L.control.zoom({ position: "topright" }).addTo(map)

  L.tileLayer("http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg", {
    subdomains: "1234",
    type: "osm",
    attribution: "Map data Tiles © MapQuest , Map data © OpenStreetMap contributors, CC-BY-SA",
    maxZoom: 18
  }).addTo(map)

  var markersDict = addLinksToMap(map, graph, showLinkinfo)

  var nodes = newnodes.concat(lostnodes).filter( function (d) {
    return "location" in d.nodeinfo
  })

  var markers = nodes.map( function (d) {
    var icon = L.AwesomeMarkers.icon({ markerColor: d.flags.online ? "green" : "red",
                                       icon: d.flags.online ? "lightbulb" : "bug" })

    var opt = { icon: icon,
                title: d.nodeinfo.hostname
              }

    var m = L.marker([d.nodeinfo.location.latitude, d.nodeinfo.location.longitude], opt)

    m.on('click', function () { return showNodeinfo(d) })
    m.bindPopup(d.nodeinfo.hostname)

    markersDict[d.nodeinfo.node_id] = m

    return m
  })

  var onlinemarkers = onlinenodes.map( function (d) {
    var opt = { color: "#76B22D",
                fillColor: "#76B22D",
                radius: 5,
                opacity: 0.7,
                fillOpacity: 0.5
              }

    var m = L.circleMarker([d.nodeinfo.location.latitude, d.nodeinfo.location.longitude], opt)

    m.on('click', function () { return showNodeinfo(d) })
    m.bindPopup(d.nodeinfo.hostname)

    markersDict[d.nodeinfo.node_id] = m

    return m
  })

  var group = L.featureGroup(markers).addTo(map)
  var group_online = L.featureGroup(onlinemarkers).addTo(map)

  var bounds = group.getBounds()

  if (!bounds.isValid())
    bounds = group_online.getBounds()

  if (bounds.isValid())
    map.fitBounds(bounds, {paddingTopLeft: [getSidebarWidth(), 0]})

  var funcDict = {}

  Object.keys(markersDict).map( function(k) {
       funcDict[k] = function (d) {
         var m = markersDict[k]
         var bounds
         if ("getBounds" in m) {
           bounds = m.getBounds()
         } else {
           bounds = L.latLngBounds([m.getLatLng()])
         }

         map.fitBounds(bounds, {paddingTopLeft: [getSidebarWidth(), 0]})
         m.openPopup(bounds.getCenter())
       }
  });

  return funcDict
}

function getSidebarWidth() {
  var small = window.matchMedia("(max-width: 60em)");
  var sb = document.getElementById("sidebar")
  return small.matches ? 0 : sb.offsetWidth
}

function addLinksToMap(map, graph, showLinkinfo) {
  var markersDict = {}

  var scale = chroma.scale(['green', 'orange', 'red']).domain([1, 10])

  var lines = graph.map( function (d) {
    var opts = { color: scale(d.tq).hex(),
                 weight: 4
               }

    var line = L.polyline(d.latlngs, opts)

    line.bindPopup(d.source.node.nodeinfo.hostname + " – " + d.target.node.nodeinfo.hostname + "
" + showDistance(d) + " / " + showTq(d) + "")
    line.on('click', function () { return showLinkinfo(d) })

    markersDict[linkId(d)] = line

    return line
  })

  var group = L.featureGroup(lines).addTo(map)

  return markersDict
}

function addToLongLinksList(el, gotoProxy, links) {
  links.forEach( function (d) {
    var row = document.createElement("tr")
    var td1 = document.createElement("td")
    var a = document.createElement("a")
    a.textContent = d.source.node.nodeinfo.hostname + " – " + d.target.node.nodeinfo.hostname
    a.href = "#"
    a.onclick = gotoProxy(d)
    td1.appendChild(a)
    row.appendChild(td1)

    var td2 = document.createElement("td")
    td2.textContent = showTq(d)
    row.appendChild(td2)

    var td3 = document.createElement("td")
    td3.textContent = showDistance(d)
    row.appendChild(td3)

    el.appendChild(row)
  })
}

function addToList(el, showContact, tf, gotoProxy, list) {
  list.forEach( function (d) {
    var time = moment(d[tf]).fromNow()

    var row = document.createElement("tr")
    var td1 = document.createElement("td")
    var a = document.createElement("a")
    a.classList.add("hostname")
    a.classList.add(d.flags.online ? "online" : "offline")
    a.textContent = d.nodeinfo.hostname
    a.href = "#"
    a.onclick = gotoProxy(d)
    td1.appendChild(a)

    if ("location" in d.nodeinfo) {
      var span = document.createElement("span")
      span.classList.add("icon")
      span.classList.add("ion-location")
      td1.appendChild(span)
    }

    if ("owner" in d.nodeinfo && showContact) {
      var contact = d.nodeinfo.owner.contact
      td1.appendChild(document.createTextNode(" – " + contact + ""))
    }

    var td2 = document.createElement("td")
    td2.textContent = time

    row.appendChild(td1)
    row.appendChild(td2)
    el.appendChild(row)
  })
}

function sum(a) {
  return a.reduce( function (a, b) {
    return a + b
  }, 0)
}

function one() {
  return 1
}

function showMeshstats(el, nodes) {
  var totalNodes = sum(nodes.filter(online).map(one))

  var totalClients = sum(nodes.filter(online).map( function (d) {
    return d.statistics.clients
  }))

  var totalGateways = sum(nodes.filter(online).filter( function (d) {
    return d.flags.gateway
  }).map(one))

  el.textContent = totalNodes + " Knoten (online), " +
                   totalClients + " Clients, " +
                   totalGateways + " Gateways"
}

function showNodeinfo(d) {
  var el = document.getElementById("nodeinfo")

  destroy()
  el.classList.remove("hidden")
  el.scrollIntoView(false)

  var closeButton = document.createElement("button")
  closeButton.classList.add("close")
  closeButton.onclick = destroy
  el.appendChild(closeButton)

  var h2 = document.createElement("h2")
  h2.textContent = d.nodeinfo.hostname
  el.appendChild(h2)

  var pre = document.createElement("pre")
  pre.textContent = JSON.stringify(d, null, ' ')
  el.appendChild(pre)

  function destroy() {
    el.classList.add("hidden")
    while (el.hasChildNodes())
      el.removeChild(el.childNodes[0])
  }
}

function showLinkinfo(d) {
}

function gotoBuilder(markers, nodes, links) {
  function gotoNode(d) {
    if (d.nodeinfo.node_id in markers)
      markers[d.nodeinfo.node_id]()

    nodes(d)

    return false
  }

  function gotoLink(d) {
    if (linkId(d) in markers)
      markers[linkId(d)]()

    links(d)

    return false
  }

  return { node: function (d) { return function () { return gotoNode(d) }},
           link: function (d) { return function () { return gotoLink(d) }}
         }
}
<|endoftext|>


<commit_before>let fs = require('fs-extra');
let glob = require('glob');
let path = require('path');
// const { createHash } = require('crypto');

const contentTypeMappingConst = {
	'.html': 'text/html',
	'.json': 'application/json',
	'.css': 'text/css',
	'.js': 'application/javascript',
	'.ico': 'image/x-icon',
	'.svg': 'image/svg+xml',
	'.eot': 'application/vnd.ms-fontobject',
	'.ttf': 'application/font-sfnt',
	'.woff': 'application/font-woff',
	'.gif': 'image/gif',
	'.zip': 'application/zip',
	'default': 'text/plain'
};

class BucketManager {
	constructor(s3Manager, bucket) {
		this.S3Manager = s3Manager;
		this.Bucket = bucket ? bucket : null;
	}

	async Deploy(contentPath, version, cacheControlRegexMap = [], contentTypeMappingOverride = {}) {
		let contentTypeMapping = Object.assign({}, contentTypeMappingConst, contentTypeMappingOverride || {});
		console.log('Deploying Website');
		const list = await new Promise((resolve, reject) => {
			glob(path.join(contentPath, '**'), { nonull: true, dot: true, nodir: true }, (error, files) => {
				error ? reject({ Title: 'Failed to get list of content files', Error: error.stack || error.toString(), Detail: error }) : resolve(files);
			});
		});

		let indexList = list.filter(file => file.match('index.html')).sort((a, b) => b.split('/').length - a.split('/').length);
		let sortedList = list.filter(file => !file.match('index.html'));

		for (const file of sortedList.concat(indexList)) {
			let relativePath = path.relative(path.resolve(contentPath), path.resolve(file));
			let relativePathUnixFormat = this.unixify(relativePath);
			let matchingCacheMap = Array.isArray(cacheControlRegexMap) && cacheControlRegexMap.find(m =>
				!m.explicit && !m.regex || m.explicit === relativePathUnixFormat || m.regex && m.regex.exec && m.regex.exec(file)
			);
			let cacheControl = matchingCacheMap && matchingCacheMap.value || cacheControlRegexMap[relativePathUnixFormat] || cacheControlRegexMap.default || 600;
			const fileUrl = this.unixify(path.join(version, relativePath));
			// const fileData = await fs.readFile(file);
			const putObjectParams = {
				Bucket: this.Bucket,
				Key: encodeURIComponent(fileUrl),
				Body: fs.createReadStream(file),
				// ContentMD5: createHash('md5').update(Buffer.from(fileData)).digest('hex'),
				ContentType: contentTypeMapping[relativePath] || contentTypeMapping[path.extname(file)] || contentTypeMapping.default || 'text/plain',
				CacheControl: typeof maxAge === 'number' ? `public, max-age=${cacheControl}` : cacheControl
			};
			try {
				await this.S3Manager.putObject(putObjectParams).promise();
				console.log(`====> ${fileUrl}`);
				// Also upload a redirect file pointing one place below and duplicate the file at /
				const unixifiedIndexFilePath = this.unixify(relativePath);
				if (unixifiedIndexFilePath.match(/\/index.html$/)) {
					// First duplicate the file at the "/" location
					const redirectFileUrl = unixifiedIndexFilePath.replace(/\/index.html$/, '');
					putObjectParams.Body = fs.createReadStream(file);
					putObjectParams.Key = encodeURIComponent(`${this.unixify(path.join(version, redirectFileUrl))}/`);
					await this.S3Manager.putObject(putObjectParams).promise();
					console.log(`   => ${decodeURIComponent(putObjectParams.Key)} (Directory Handler)`);

					// Then add a redirect from the base location to the "/"
					const redirectFile = await fs.readFile(path.join(__dirname, './appRedirect.html'));
					const updatedRedirectFile = redirectFile.toString().replace('{{PATH}}', redirectFileUrl);
					putObjectParams.Body = Buffer.from(updatedRedirectFile);
					putObjectParams.Key = encodeURIComponent(this.unixify(path.join(version, redirectFileUrl)));
					// putObjectParams.ContentMD5 = createHash('md5').update(Buffer.from(updatedRedirectFile)).digest('hex');
					await this.S3Manager.putObject(putObjectParams).promise();
					console.log(`   => ${decodeURIComponent(putObjectParams.Key)} (Redirect)`);
				}
			} catch (failure) {
				throw { File: file, Error: failure.stack || failure.toString(), Detail: failure };
			}
		}

		return { Title: 'Upload Success.', Bucket: this.Bucket, Version: version };
	}

	DeployLambdaPromise(bucket, localPath, remotePath) {
		return this.S3Manager.upload({
			Bucket: bucket || this.Bucket,
			Key: this.unixify(remotePath),
			Body: fs.createReadStream(localPath),
			ContentType: contentTypeMappingConst[path.extname(remotePath)] || contentTypeMappingConst.default || 'text/plain',
			CacheControl: 'public, max-age=10'
		}).promise()
		.then(() => { console.log(`====> ${remotePath}`); })
		.catch(failure => {
			throw { File: localPath, Detail: failure };
		});
	}

	CopyBucket(source, target) {
		let listParams = {
			Bucket: this.Bucket,
			Delimiter: ',',
			EncodingType: 'url',
			//FetchOwner: true || false,
			//MaxKeys: 0
			Prefix: source
		};
		return this.S3Manager.listObjectsV2(listParams).promise()
		.then(data => {
			if (data.IsTruncated) { throw ({ Title: 'Failed to copy source', Error: 'Too many objects present.' }); }
			return data.Contents.map(item => item.Key).filter(key => !key.match(/\/$/)).reduce((listPromise, key) => {
				return listPromise.then(() => {
					return this.S3Manager.copyObject({
						Bucket: this.Bucket,
						Key: this.unixify(path.join(target, path.relative(source, key))),
						CopySource: `${this.Bucket}/${this.unixify(key)}`
					}).promise()
					.catch(failure => Promise.reject({ Source: key, Error: failure.stack || failure.toString(), Detail: failure }));
				}).then(() => Promise.resolve({ Title: 'Promote to stage success', Bucket: this.Bucket, Source: source, Target: target }));
			}, Promise.resolve([]));
		});
	}

	// ensures a path will be in unix format (that is, forward slash), also on Windows systems.
	unixify(fullPath) {
		return fullPath.replace(/\\/g, '/');
	}
}

module.exports = BucketManager;
<commit_msg>Add MD5 hash validation.<commit_after>let fs = require('fs-extra');
let glob = require('glob');
let path = require('path');
const { createHash } = require('crypto');

const contentTypeMappingConst = {
	'.html': 'text/html',
	'.json': 'application/json',
	'.css': 'text/css',
	'.js': 'application/javascript',
	'.ico': 'image/x-icon',
	'.svg': 'image/svg+xml',
	'.eot': 'application/vnd.ms-fontobject',
	'.ttf': 'application/font-sfnt',
	'.woff': 'application/font-woff',
	'.gif': 'image/gif',
	'.zip': 'application/zip',
	'default': 'text/plain'
};

class BucketManager {
	constructor(s3Manager, bucket) {
		this.S3Manager = s3Manager;
		this.Bucket = bucket ? bucket : null;
	}

	async Deploy(contentPath, version, cacheControlRegexMap = [], contentTypeMappingOverride = {}) {
		let contentTypeMapping = Object.assign({}, contentTypeMappingConst, contentTypeMappingOverride || {});
		console.log('Deploying Website');
		const list = await new Promise((resolve, reject) => {
			glob(path.join(contentPath, '**'), { nonull: true, dot: true, nodir: true }, (error, files) => {
				error ? reject({ Title: 'Failed to get list of content files', Error: error.stack || error.toString(), Detail: error }) : resolve(files);
			});
		});

		let indexList = list.filter(file => file.match('index.html')).sort((a, b) => b.split('/').length - a.split('/').length);
		let sortedList = list.filter(file => !file.match('index.html'));

		for (const file of sortedList.concat(indexList)) {
			let relativePath = path.relative(path.resolve(contentPath), path.resolve(file));
			let relativePathUnixFormat = this.unixify(relativePath);
			let matchingCacheMap = Array.isArray(cacheControlRegexMap) && cacheControlRegexMap.find(m =>
				!m.explicit && !m.regex || m.explicit === relativePathUnixFormat || m.regex && m.regex.exec && m.regex.exec(file)
			);
			let cacheControl = matchingCacheMap && matchingCacheMap.value || cacheControlRegexMap[relativePathUnixFormat] || cacheControlRegexMap.default || 600;
			const fileUrl = this.unixify(path.join(version, relativePath));
			const fileData = await fs.readFile(file);
			const putObjectParams = {
				Bucket: this.Bucket,
				Key: fileUrl,
				Body: fileData,
				ContentMD5: createHash('md5').update(fileData).digest('base64'),
				ContentType: contentTypeMapping[relativePath] || contentTypeMapping[path.extname(file)] || contentTypeMapping.default || 'text/plain',
				CacheControl: typeof maxAge === 'number' ? `public, max-age=${cacheControl}` : cacheControl
			};
			try {
				await this.S3Manager.putObject(putObjectParams).promise();
				console.log(`====> ${fileUrl}`);
				// Also upload a redirect file pointing one place below and duplicate the file at /
				const unixifiedIndexFilePath = this.unixify(relativePath);
				if (unixifiedIndexFilePath.match(/\/index.html$/)) {
					// First duplicate the file at the "/" location
					const redirectFileUrl = unixifiedIndexFilePath.replace(/\/index.html$/, '');
					putObjectParams.Body = fileData;
					putObjectParams.Key = `${this.unixify(path.join(version, redirectFileUrl))}/`;
					await this.S3Manager.putObject(putObjectParams).promise();
					console.log(`   => ${putObjectParams.Key} (Directory Handler)`);

					// Then add a redirect from the base location to the "/"
					const redirectFile = await fs.readFile(path.join(__dirname, './appRedirect.html'));
					const updatedRedirectFile = redirectFile.toString().replace('{{PATH}}', redirectFileUrl);
					putObjectParams.Body = Buffer.from(updatedRedirectFile);
					putObjectParams.Key = this.unixify(path.join(version, redirectFileUrl));
					putObjectParams.ContentMD5 = createHash('md5').update(updatedRedirectFile).digest('base64');
					await this.S3Manager.putObject(putObjectParams).promise();
					console.log(`   => ${putObjectParams.Key} (Redirect)`);
				}
			} catch (failure) {
				throw { File: file, Error: failure.stack || failure.toString(), Detail: failure };
			}
		}

		return { Title: 'Upload Success.', Bucket: this.Bucket, Version: version };
	}

	DeployLambdaPromise(bucket, localPath, remotePath) {
		return this.S3Manager.upload({
			Bucket: bucket || this.Bucket,
			Key: this.unixify(remotePath),
			Body: fs.createReadStream(localPath),
			ContentType: contentTypeMappingConst[path.extname(remotePath)] || contentTypeMappingConst.default || 'text/plain',
			CacheControl: 'public, max-age=10'
		}).promise()
		.then(() => { console.log(`====> ${remotePath}`); })
		.catch(failure => {
			throw { File: localPath, Detail: failure };
		});
	}

	CopyBucket(source, target) {
		let listParams = {
			Bucket: this.Bucket,
			Delimiter: ',',
			EncodingType: 'url',
			//FetchOwner: true || false,
			//MaxKeys: 0
			Prefix: source
		};
		return this.S3Manager.listObjectsV2(listParams).promise()
		.then(data => {
			if (data.IsTruncated) { throw ({ Title: 'Failed to copy source', Error: 'Too many objects present.' }); }
			return data.Contents.map(item => item.Key).filter(key => !key.match(/\/$/)).reduce((listPromise, key) => {
				return listPromise.then(() => {
					return this.S3Manager.copyObject({
						Bucket: this.Bucket,
						Key: this.unixify(path.join(target, path.relative(source, key))),
						CopySource: `${this.Bucket}/${this.unixify(key)}`
					}).promise()
					.catch(failure => Promise.reject({ Source: key, Error: failure.stack || failure.toString(), Detail: failure }));
				}).then(() => Promise.resolve({ Title: 'Promote to stage success', Bucket: this.Bucket, Source: source, Target: target }));
			}, Promise.resolve([]));
		});
	}

	// ensures a path will be in unix format (that is, forward slash), also on Windows systems.
	unixify(fullPath) {
		return fullPath.replace(/\\/g, '/');
	}
}

module.exports = BucketManager;
<|endoftext|>


<commit_before>import React from 'react';
import {graphql, createFragmentContainer} from 'react-relay';
import PropTypes from 'prop-types';
import {autobind} from 'core-decorators';

import PrInfoContainer from './pr-info-container';
import PrUrlInputBox from '../views/pr-url-input-box';
import Octicon from '../views/octicon';
import {RemotePropType, BranchSetPropType} from '../prop-types';

export class PrSelectionByBranch extends React.Component {
  static propTypes = {
    repository: PropTypes.shape({
      defaultBranchRef: PropTypes.shape({
        name: PropTypes.string.isRequired,
      }).isRequired,
      pullRequests: PropTypes.shape({
        totalCount: PropTypes.number.isRequired,
        edges: PropTypes.arrayOf(PropTypes.shape({
          node: PropTypes.shape({
            id: PropTypes.string.isRequired,
            number: PropTypes.number.isRequired,
            title: PropTypes.string.isRequired,
            url: PropTypes.string.isRequired,
          }).isRequired,
        })).isRequired,
      }),
    }),
    onSelectPr: PropTypes.func.isRequired,
    onUnpinPr: PropTypes.func.isRequired,
    onCreatePr: PropTypes.func.isRequired,
    onSearchAgain: PropTypes.func.isRequired,
    variables: PropTypes.shape({
      repoOwner: PropTypes.string.isRequired,
      repoName: PropTypes.string.isRequired,
      branchName: PropTypes.string.isRequired,
    }),
    remote: RemotePropType,
    aheadCount: PropTypes.number,
    branches: BranchSetPropType.isRequired,
    pushInProgress: PropTypes.bool.isRequired,
  }

  constructor(props, context) {
    super(props, context);
    this.state = {displayInputBox: false};
  }

  render() {
    return (

        {this.renderSubview()}

    );
  }

  renderSubview() {
    const repo = this.props.repository;
    const {variables} = this.props;
    if (!repo || !repo.pullRequests.edges.length) {
      return this.renderCreatePr();
    }

    const edges = repo.pullRequests.edges;
    if (edges.length === 1) {
      return (

              <Octicon
                title="Click here to select another PR."
                icon="pin"
                className="pinned-by-url"
              />
              Specify Pull Request URL to pin

            {this.state.displayInputBox &&
              <PrUrlInputBox onSubmit={this.props.onSelectPr}>

                  We found a pull request associated with the branch {variables.branchName} on the
                  repository {variables.repoOwner}/{variables.repoName}.

                  You can manually pin a different GitHub pull request to the current branch by entering its URL:

              </PrUrlInputBox>
            }

          <PrInfoContainer pullRequest={edges[0].node} />

      );
    }

    return this.renderPrSelectionList(edges, repo.pullRequests.totalCount);
  }

  renderCreatePr() {
    return (

            <Octicon className="github-CreatePr-icon" icon="git-pull-request" />

New Pull Request

            {this.renderCreatePrControl()}

          <PrUrlInputBox onSubmit={this.props.onSelectPr}>

              Search again
              to discover an existing pull request, or manually link a GitHub pull request to the current branch by
              entering its URL:

          </PrUrlInputBox>

    );
  }

  renderCreatePrControl() {
    if (this.isDetachedHead()) {
      return (

          You are not currently on any branch.
           Create a new branch
          to share your work with a pull request.

      );
    }

    if (this.isOnDefaultRef()) {
      return (

          You are currently on your repository's default branch.
           Create a new branch
          to share your work with a pull request.

      );
    }

    if (this.isSameAsDefaultRef()) {
      return (

          Your current branch has not moved from the repository's default branch.
          Make some commits
          to share your work with a pull request.

      );
    }

    let message = 'Open new pull request';
    let disable = false;
    if (this.props.pushInProgress) {
      message = 'Pushing...';
      disable = true;
    } else if (!this.hasUpstreamBranch()) {
      message = 'Publish + open new pull request';
    } else if (this.props.aheadCount > 0) {
      message = 'Push + open new pull request';
    }

    return (

          <button
            className="github-PrSelectionByBranch-createPr btn btn-primary"
            onClick={this.props.onCreatePr}
            disabled={disable}>
            {message}
          </button>

    );
  }

  renderPrSelectionList(edges, totalCount) {
    const {variables} = this.props;
    return (

          We found {totalCount} pull requests associated
          with a branch named {variables.branchName} on the
          repository {variables.repoOwner}/{variables.repoName}.
          Select a pull request below to display it, or specify
          any pull request URL to pin it manually:

          <PrUrlInputBox onSubmit={this.props.onSelectPr} />

          {edges.map(this.renderPrItem)}

    );
  }

  @autobind
  renderPrItem({node}) {
    return (

 this.selectPullRequest(e, node)}>
        #{node.number}: {node.title}

    );
  }

  @autobind
  toggleInputBoxVisibility() {
    this.setState({displayInputBox: !this.state.displayInputBox});
  }

  @autobind
  setPr(prLink) {
    this.props.onSelectPr(prLink);
  }

  @autobind
  selectPullRequest(event, node) {
    event.preventDefault();
    this.setPr(node.url);
  }

  getDefaultBranchRef() {
    return `refs/heads/${this.props.repository.defaultBranchRef.name}`;
  }

  isDetachedHead() {
    return !this.props.branches.getHeadBranch().isPresent();
  }

  isOnDefaultRef() {
    if (!this.props.repository) { return false; }

    const currentBranch = this.props.branches.getHeadBranch();
    return currentBranch.getPush().getRemoteRef() === this.getDefaultBranchRef();
  }

  isSameAsDefaultRef() {
    if (!this.props.repository) { return false; }

    const currentBranch = this.props.branches.getHeadBranch();
    const mainBranches = this.props.branches.getPushSources(this.props.remote.getName(), this.getDefaultBranchRef());
    return mainBranches.some(branch => branch.getSha() === currentBranch.getSha());
  }

  hasUpstreamBranch() {
    return this.props.branches.getHeadBranch().getUpstream().isPresent();
  }
}

export default createFragmentContainer(PrSelectionByBranch, {
  repository: graphql`
    fragment prSelectionByBranchContainer_repository on Repository {
      defaultBranchRef {
        name
      }

      pullRequests(first: 30, headRefName: $branchName) {
        totalCount
        edges {
          node {
            id number title url
            ...prInfoContainer_pullRequest
          }
        }
      }
    }
  `,
});
<commit_msg>Detect when the current branch has been pushed to a different remote<commit_after>import React from 'react';
import {graphql, createFragmentContainer} from 'react-relay';
import PropTypes from 'prop-types';
import {autobind} from 'core-decorators';

import PrInfoContainer from './pr-info-container';
import PrUrlInputBox from '../views/pr-url-input-box';
import Octicon from '../views/octicon';
import {RemotePropType, BranchSetPropType} from '../prop-types';

export class PrSelectionByBranch extends React.Component {
  static propTypes = {
    repository: PropTypes.shape({
      defaultBranchRef: PropTypes.shape({
        name: PropTypes.string.isRequired,
      }).isRequired,
      pullRequests: PropTypes.shape({
        totalCount: PropTypes.number.isRequired,
        edges: PropTypes.arrayOf(PropTypes.shape({
          node: PropTypes.shape({
            id: PropTypes.string.isRequired,
            number: PropTypes.number.isRequired,
            title: PropTypes.string.isRequired,
            url: PropTypes.string.isRequired,
          }).isRequired,
        })).isRequired,
      }),
    }),
    onSelectPr: PropTypes.func.isRequired,
    onUnpinPr: PropTypes.func.isRequired,
    onCreatePr: PropTypes.func.isRequired,
    onSearchAgain: PropTypes.func.isRequired,
    variables: PropTypes.shape({
      repoOwner: PropTypes.string.isRequired,
      repoName: PropTypes.string.isRequired,
      branchName: PropTypes.string.isRequired,
    }),
    remote: RemotePropType,
    aheadCount: PropTypes.number,
    branches: BranchSetPropType.isRequired,
    pushInProgress: PropTypes.bool.isRequired,
  }

  constructor(props, context) {
    super(props, context);
    this.state = {displayInputBox: false};
  }

  render() {
    return (

        {this.renderSubview()}

    );
  }

  renderSubview() {
    const repo = this.props.repository;
    const {variables} = this.props;
    if (!repo || !repo.pullRequests.edges.length) {
      return this.renderCreatePr();
    }

    const edges = repo.pullRequests.edges;
    if (edges.length === 1) {
      return (

              <Octicon
                title="Click here to select another PR."
                icon="pin"
                className="pinned-by-url"
              />
              Specify Pull Request URL to pin

            {this.state.displayInputBox &&
              <PrUrlInputBox onSubmit={this.props.onSelectPr}>

                  We found a pull request associated with the branch {variables.branchName} on the
                  repository {variables.repoOwner}/{variables.repoName}.

                  You can manually pin a different GitHub pull request to the current branch by entering its URL:

              </PrUrlInputBox>
            }

          <PrInfoContainer pullRequest={edges[0].node} />

      );
    }

    return this.renderPrSelectionList(edges, repo.pullRequests.totalCount);
  }

  renderCreatePr() {
    return (

            <Octicon className="github-CreatePr-icon" icon="git-pull-request" />

New Pull Request

            {this.renderCreatePrControl()}

          <PrUrlInputBox onSubmit={this.props.onSelectPr}>

              Search again
              to discover an existing pull request, or manually link a GitHub pull request to the current branch by
              entering its URL:

          </PrUrlInputBox>

    );
  }

  renderCreatePrControl() {
    if (this.isDetachedHead()) {
      return (

          You are not currently on any branch.
           Create a new branch
          to share your work with a pull request.

      );
    }

    if (this.isOnDefaultRef()) {
      return (

          You are currently on your repository's default branch.
           Create a new branch
          to share your work with a pull request.

      );
    }

    if (this.isSameAsDefaultRef()) {
      return (

          Your current branch has not moved from the repository's default branch.
          Make some commits
          to share your work with a pull request.

      );
    }

    let message = 'Open new pull request';
    let disable = false;
    const differentRemote = this.pushesToDifferentRemote();
    if (this.props.pushInProgress) {
      message = 'Pushing...';
      disable = true;
    } else if (!this.hasUpstreamBranch() || differentRemote) {
      message = 'Publish + open new pull request';
    } else if (this.props.aheadCount > 0) {
      message = 'Push + open new pull request';
    }

    return (

        {differentRemote &&

            Your current branch is configured to push to the remote
            {this.props.branches.getHeadBranch().getPush().getRemoteName()}.

        }

          <button
            className="github-PrSelectionByBranch-createPr btn btn-primary"
            onClick={this.props.onCreatePr}
            disabled={disable}>
            {message}
          </button>

    );
  }

  renderPrSelectionList(edges, totalCount) {
    const {variables} = this.props;
    return (

          We found {totalCount} pull requests associated
          with a branch named {variables.branchName} on the
          repository {variables.repoOwner}/{variables.repoName}.
          Select a pull request below to display it, or specify
          any pull request URL to pin it manually:

          <PrUrlInputBox onSubmit={this.props.onSelectPr} />

          {edges.map(this.renderPrItem)}

    );
  }

  @autobind
  renderPrItem({node}) {
    return (

 this.selectPullRequest(e, node)}>
        #{node.number}: {node.title}

    );
  }

  @autobind
  toggleInputBoxVisibility() {
    this.setState({displayInputBox: !this.state.displayInputBox});
  }

  @autobind
  setPr(prLink) {
    this.props.onSelectPr(prLink);
  }

  @autobind
  selectPullRequest(event, node) {
    event.preventDefault();
    this.setPr(node.url);
  }

  getDefaultBranchRef() {
    return `refs/heads/${this.props.repository.defaultBranchRef.name}`;
  }

  isDetachedHead() {
    return !this.props.branches.getHeadBranch().isPresent();
  }

  isOnDefaultRef() {
    if (!this.props.repository) { return false; }

    const currentBranch = this.props.branches.getHeadBranch();
    return currentBranch.getPush().getRemoteRef() === this.getDefaultBranchRef();
  }

  isSameAsDefaultRef() {
    if (!this.props.repository) { return false; }

    const currentBranch = this.props.branches.getHeadBranch();
    const mainBranches = this.props.branches.getPushSources(this.props.remote.getName(), this.getDefaultBranchRef());
    return mainBranches.some(branch => branch.getSha() === currentBranch.getSha());
  }

  pushesToDifferentRemote() {
    const p = this.props.branches.getHeadBranch().getPush();
    if (!p.isRemoteTracking()) { return false; }

    const pushRemoteName = p.getRemoteName();
    return pushRemoteName !== this.props.remote.getName();
  }

  hasUpstreamBranch() {
    return this.props.branches.getHeadBranch().getUpstream().isPresent();
  }
}

export default createFragmentContainer(PrSelectionByBranch, {
  repository: graphql`
    fragment prSelectionByBranchContainer_repository on Repository {
      defaultBranchRef {
        name
      }

      pullRequests(first: 30, headRefName: $branchName) {
        totalCount
        edges {
          node {
            id number title url
            ...prInfoContainer_pullRequest
          }
        }
      }
    }
  `,
});
<|endoftext|>


<commit_before>var printFailedLine = function(what,failedPeers, notTriedPeers,successCount) {

    if(!notTriedPeers || !failedPeers ||  (failedPeers.length + successCount) <=0){
        return;
    }
    console.log(what + " failed peers count : " + failedPeers.length + " [" + ((failedPeers.length * 100) / (successCount + failedPeers.length)) + " %]");

    failedPeers.forEach(function(peer) {
        console.log("- Peer ID : " + peer.name + ", Tried : " + peer.connections);
    });

    console.log(what + " never tried peers count : " + notTriedPeers.length + " [" + ((notTriedPeers.length * 100) / (successCount + failedPeers.length + notTriedPeers.length)) + " %]");

    notTriedPeers.forEach(function(peer) {
        console.log("- Peer ID : " + peer.name);
    });
}

var printMinMaxLine  = function(list) {
    if(!list || list.length <= 0){
        console.log('Results list does not contain any items');
        return;
    }
    console.log('Result count ' + list.length + ', range ' + list[0].time + ' ms to  '  + list[(list.length - 1)].time + " ms.");
}

var printResultLine  = function(what, list) {
    console.log(what + " : 100% : " + getValueOf(list,1.00) + " ms, 99% : " + getValueOf(list,0.99)  + " ms, 95 : " + getValueOf(list,0.95)  + " ms, 90% : " + getValueOf(list,0.90) + " ms.");
}

var printAverageDataRate = function (list) {
    var amountOfResults = list.length;
    var cumulativeTime = 0;
    var cumulativeData = 0;
    for (var i = 0; i < amountOfResults; i++) {
        var listItem = list[i];
        if (listItem.result === 'OK') {
            cumulativeTime += listItem.time * listItem.doneRounds;
            cumulativeData += listItem.dataAmount * listItem.doneRounds;
        }
    }
    // The average rate is calculated by first getting the rate in KB per second
    // and then rounding it. The final print is done in MB per second.
    console.log('Average data rate: ' + (Math.round((cumulativeData / 1000) / (cumulativeTime / 1000)) / 1000) + ' MB/s');
};

var preProcessResults  = function(source, target,errorTarget){

    if(!target) {
        target = [];
    }
    if(!errorTarget.failedPeer) {
        errorTarget.failedPeer = [];
    }
    if(!errorTarget.notTriedList) {
        errorTarget.notTriedList = [];
    }

    source.forEach(function(roundResult) {

        if(!roundResult || roundResult == null){
            return;
        }

        if (roundResult.result == "OK") {
            target.push(roundResult);
        } else if(roundResult.connections){
            errorTarget.failedPeer.push(roundResult);
        }else{ // if connections is zero, then we never got to try to connect before we got timeout
            errorTarget.notTriedList.push(roundResult);
        }
    });
}

var getValueOf  = function(array, presentage) {

    if(array.length <= 0){
        return;
    }

    var index = Math.round(array.length * presentage);
    if(index > 0){
        index = index - 1;
    }
    if(index < array.length) {
        return array[index].time;
    }
}

var extendArray  = function(source, target) {
    if(!target)
        return source;
    return target.concat(source);
}
var compare  = function (a,b) {
    if (a.time < b.time)
        return -1;
    if (a.time > b.time)
        return 1;
    return 0;
}

module.exports.process = function (testResults, testDevices) {
    var results = {};
    var combined ={};

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

        if(testResults[i].data) {
            if (!results[testResults[i].device]) {
                results[testResults[i].device] = {};
            }

            if (testResults[i].data.peersList) {
                results[testResults[i].device].peersList = extendArray(testResults[i].data.peersList, results[testResults[i].device].peersList);
            } else if (testResults[i].data.connectList) {
                if(!results[testResults[i].device].connectList) {
                    results[testResults[i].device].connectList = [];
                }

                if(!results[testResults[i].device].connectError) {
                    results[testResults[i].device].connectError = {};
                }

                preProcessResults(testResults[i].data.connectList,results[testResults[i].device].connectList,results[testResults[i].device].connectError);
            } else if (testResults[i].data.sendList) {
                if(!results[testResults[i].device].sendList) {
                    results[testResults[i].device].sendList = [];
                }

                if(!results[testResults[i].device].sendError) {
                    results[testResults[i].device].sendError = {};
                }

                preProcessResults(testResults[i].data.sendList,results[testResults[i].device].sendList,results[testResults[i].device].sendError);
            } else {
                console.log('Test[' + testResults[i].test + '] for ' + testResults[i].device + ' has unknown data : ' + JSON.stringify(testResults[i].data));
            }
        }
    }

    console.log('--------------- test report ---------------------');

    var counter = 0;
    for( var devName in results){

        counter++;
        console.log('--------------- ' + devName + ' --------------------- : ' + counter);

        if(results[devName].peersList){// && (results[devName].peersList.length > 0)) {
            results[devName].peersList.sort(compare);

            printResultLine('peersList',results[devName].peersList);
            printMinMaxLine(results[devName].peersList);
            combined.peersList = extendArray(results[devName].peersList,combined.peersList);
        }

        if(results[devName].connectList){// && (results[devName].connectList.length > 0)) {
            results[devName].connectList.sort(compare);

            printResultLine('connectList',results[devName].connectList);
            printMinMaxLine(results[devName].connectList);

            if(results[devName].connectError) {
                printFailedLine('connectList',results[devName].connectError.failedPeer, results[devName].connectError.notTriedList, results[devName].connectList.length);
            }
            combined.connectList = extendArray(results[devName].connectList,combined.connectList);
        }else if (results[devName].connectError && results[devName].connectError.failedPeer > 0){
            console.log("All (" + results[devName].connectError.failedPeer + ") Re-Connect test connections failed");
        }

        if(results[devName].sendList){// && (results[devName].sendList.length > 0)) {
            results[devName].sendList.sort(compare);

            printResultLine('sendList',results[devName].sendList);
            printAverageDataRate(results[devName].sendList);
            printMinMaxLine(results[devName].sendList);

            if(results[devName].sendError) {
                printFailedLine('sendList',results[devName].sendError.failedPeer, results[devName].sendError.notTriedList, results[devName].sendList.length);
            }
            combined.sendList = extendArray(results[devName].sendList,combined.sendList);
        }else if (results[devName].sendError && results[devName].sendError.failedPeer > 0){
            console.log("All (" + results[devName].sendError.failedPeer + ") SendData test connections failed");
        }
    }

    console.log('--------------- Combined ---------------------');

    if(combined.peersList){
        combined.peersList.sort(compare);
        printResultLine('peersList',combined.peersList);
    }

    if(combined.connectList){
        combined.connectList.sort(compare);
        printResultLine('connectList',combined.connectList);
    }

    if(combined.sendList){
        combined.sendList.sort(compare);
        printResultLine('sendList',combined.sendList);
        printAverageDataRate(combined.sendList);
   }

    console.log('--------------- end of test report ---------------------');

    return results;
};
<commit_msg>To Style, parse json<commit_after>var printFailedLine = function(what, failedPeers, notTriedPeers, successCount) {

  if (!notTriedPeers || !failedPeers || (failedPeers.length + successCount) <= 0) {
    return;
  }

  console.log(
    what + " failed peers count : " + failedPeers.length + " [" +
    ((failedPeers.length * 100) / (successCount + failedPeers.length)) + " %]"
  );

  failedPeers.forEach(function(peer) {
    console.log("- Peer ID : " + peer.name + ", Tried : " + peer.connections);
  });

  console.log(
    what + " never tried peers count : " + notTriedPeers.length +
    " [" + ((notTriedPeers.length * 100) / (successCount + failedPeers.length +
    notTriedPeers.length)) + " %]"
  );

  notTriedPeers.forEach(function(peer) {
    console.log("- Peer ID : " + peer.name);
  });
}

var printMinMaxLine  = function(list) {
  if (!list || list.length <= 0){
    console.log('Results list does not contain any items');
    return;
  }

  console.log(
    'Result count ' + list.length + ', range ' + list[0].time + ' ms to  '  +
    list[(list.length - 1)].time + " ms."
  );
}

var printResultLine = function(what, list) {
  console.log(
    what + " : 100% : " + getValueOf(list,1.00) + " ms, 99% : " +
    getValueOf(list,0.99)  + " ms, 95 : " + getValueOf(list,0.95)  + " ms, 90% : " +
    getValueOf(list,0.90) + " ms."
  );
}

var printAverageDataRate = function (list) {

  var amountOfResults = list.length;
  var cumulativeTime = 0;
  var cumulativeData = 0;

  for (var i = 0; i < amountOfResults; i++) {
    var listItem = list[i];
    if (listItem.result === 'OK') {
      cumulativeTime += listItem.time * listItem.doneRounds;
      cumulativeData += listItem.dataAmount * listItem.doneRounds;
    }
  }

  // The average rate is calculated by first getting the rate in KB per second
  // and then rounding it. The final print is done in MB per second.
  console.log(
    'Average data rate: ' +
    (Math.round((cumulativeData / 1000) / (cumulativeTime / 1000)) / 1000) + ' MB/s'
  );
};

var preProcessResults = function(source, target, errorTarget){

  if (!target) {
    target = [];
  }

  if (!errorTarget.failedPeer) {
    errorTarget.failedPeer = [];
  }

  if (!errorTarget.notTriedList) {
    errorTarget.notTriedList = [];
  }

  source.forEach(function(roundResult) {

    if (!roundResult || roundResult == null){
      return;
    }

    if (roundResult.result == "OK") {
      target.push(roundResult);
    } else if(roundResult.connections){
      errorTarget.failedPeer.push(roundResult);
    } else { // if connections is zero, then we never got to try to connect before we got timeout
      errorTarget.notTriedList.push(roundResult);
    }
  });
}

var getValueOf = function(array, presentage) {

  if (array.length <= 0) {
    return;
  }

  var index = Math.round(array.length * presentage);
  if (index > 0) {
    index = index - 1;
  }

  if (index < array.length) {
    return array[index].time;
  }
}

var extendArray = function(source, target) {
  if (!target)
    return source;
  return target.concat(source);
}

var compare = function (a,b) {
  if (a.time < b.time)
    return -1;
  if (a.time > b.time)
    return 1;
  return 0;
}

module.exports.process = function (testResults, testDevices) {

  var results = {};
  var combined ={};

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

    var result = JSON.parse(result);

    if (result.data) {

      if (!results[result.device]) {
        results[result.device] = {};
      }

      if (result.data.peersList) {

        results[result.device].peersList =
          extendArray(result.data.peersList, results[result.device].peersList);

      } else if (result.data.connectList) {

        if (!results[result.device].connectList) {
          results[result.device].connectList = [];
        }

        if(!results[result.device].connectError) {
          results[result.device].connectError = {};
        }

        preProcessResults(
          result.data.connectList,
          results[result.device].connectList,
          results[result.device].connectError
        );

      } else if (result.data.sendList) {

        if (!results[result.device].sendList) {
          results[result.device].sendList = [];
        }

        if (!results[result.device].sendError) {
          results[result.device].sendError = {};
        }

        preProcessResults(
          result.data.sendList,
          results[result.device].sendList,
          results[result.device].sendError
        );
      } else {
        console.log(
          'Test[' + result.test + '] for ' + result.device + ' has unknown data : ' +
          JSON.stringify(result.data)
        );
      }
    }
  }

  console.log('--------------- test report ---------------------');

  var counter = 0;
  for (var devName in results) {

    counter++;
    console.log('--------------- ' + devName + ' --------------------- : ' + counter);

    if (results[devName].peersList) {// && (results[devName].peersList.length > 0)) {

      results[devName].peersList.sort(compare);

      printResultLine('peersList',results[devName].peersList);
      printMinMaxLine(results[devName].peersList);
      combined.peersList = extendArray(results[devName].peersList,combined.peersList);
    }

    if (results[devName].connectList) {// && (results[devName].connectList.length > 0)) {
      results[devName].connectList.sort(compare);

      printResultLine('connectList',results[devName].connectList);
      printMinMaxLine(results[devName].connectList);

      if (results[devName].connectError) {

        printFailedLine(
          'connectList',
          results[devName].connectError.failedPeer,
          results[devName].connectError.notTriedList,
          results[devName].connectList.length
        );
      }
      combined.connectList = extendArray(results[devName].connectList,combined.connectList);

    } else if (results[devName].connectError && results[devName].connectError.failedPeer > 0) {
      console.log(
        "All (" + results[devName].connectError.failedPeer +
        ") Re-Connect test connections failed"
      );
    }

    if (results[devName].sendList) {// && (results[devName].sendList.length > 0)) {

      results[devName].sendList.sort(compare);

      printResultLine('sendList',results[devName].sendList);
      printAverageDataRate(results[devName].sendList);
      printMinMaxLine(results[devName].sendList);

      if (results[devName].sendError) {
        printFailedLine(
          'sendList',
          results[devName].sendError.failedPeer,
          results[devName].sendError.notTriedList,
          results[devName].sendList.length
        );
      }

      combined.sendList = extendArray(results[devName].sendList,combined.sendList);

    } else if (results[devName].sendError && results[devName].sendError.failedPeer > 0) {

      console.log(
        "All (" + results[devName].sendError.failedPeer +
        ") SendData test connections failed"
      );

    }
  }

  console.log('--------------- Combined ---------------------');

  if (combined.peersList) {
    combined.peersList.sort(compare);
    printResultLine('peersList',combined.peersList);
  }

  if (combined.connectList) {
    combined.connectList.sort(compare);
    printResultLine('connectList',combined.connectList);
  }

  if (combined.sendList) {
    combined.sendList.sort(compare);
    printResultLine('sendList',combined.sendList);
    printAverageDataRate(combined.sendList);
 }

  console.log('--------------- end of test report ---------------------');

  return results;
};
<|endoftext|>


<commit_before>"use strict";
import React, { Component } from "react";
import {
  StyleSheet,
  Text,
  View,
  TextInput,
  ListView,
  RecyclerViewBackedScrollView,
  TouchableHighlight,
  Alert,
  RefreshControl,
  Image,
  ScrollView,
  DatePickerIOS
} from "react-native";
import YANavigator from 'react-native-ya-navigator';
import { CompassAPI } from "./compass_api";
import { SchoolSelectionView } from "./login_ui";
const compassAPI = new CompassAPI();
var ScrollableTabView = require("react-native-scrollable-tab-view");
import { Button, Card } from 'react-native-material-design';
import renderIf from "render-if";
import IconTabBar from "./icon_tab_bar";

class NewsView extends Component {
  async refresh() {
    this.setState({
      refreshing: true
    });
    var homeFeed = await compassAPI.homeContent();
    if (homeFeed) {
      var newsItems = homeFeed["news"];
      this.setState({
        items: newsItems,
        refreshing: false
      });
    } else {
      console.log("Could not refresh home feed. Are you logged in?");
    }
  }
  constructor(props, context) {
    super(props, context);
    this.state = {items:[], refreshing: false}
    this.refresh();
  }
  render() {
    let cardArray = this.state.items.map((item, index) => {return(<Card key={index}>
          <Card.Body>
            <View style={{flexDirection:"row", flexWrap:"nowrap", alignItems:"center", justifyContent:"center", marginBottom: 10}}>
            <Text style={{fontSize: 26, flex:1}}>{item["UploadedBy"]}</Text>
            <Image source={{uri: "https://"+compassAPI.compassURL+item["UserImageUrl"]}} style={{width:76, height:76, borderRadius: 38}} />
            </View>
            <Text>{item["Content"]}</Text>
          </Card.Body>
        </Card>)});
    return (
      <ScrollView contentContainerStyle={{flex: this.state.items.length === 0 ? 1 : 0}} refreshControl={
        <RefreshControl refreshing={this.state.refreshing} onRefresh={this.refresh.bind(this)} />
      }>
        {cardArray}
        {renderIf(this.state.items.length === 0)(
          <View style={{flex: 1, justifyContent: "center", alignItems: "center"}}>
            <Text style={{fontSize: 28, textAlign: "center", marginBottom: 10}}>No news items.</Text>
            <Text style={{fontSize: 20, textAlign: "center"}}>Pull to check for new items.</Text>
          </View>
        )}
      </ScrollView>
    );
  }
}

class ScheduleView extends Component {
  async refresh() {
    this.setState({
      refreshing: true
    });
    var schedule = await compassAPI.scheduleForDate(this.state.date.toISOString().substring(0,10));
    if (schedule) {
      this.setState({
        items: schedule,
        refreshing: false
      });
    } else {
      console.log("Could not refresh today's schedule. Are you logged in?");
    }
  }
  constructor(props, context) {
    super(props, context);
    this.state = {items:[], refreshing: false, date: new Date(), showDatePicker: false}
    this.refresh();
  }
  async onDateChange(date) {
    await this.setState({date: date});
    this.refresh();
  }
  render() {
    let cardArray = this.state.items.map((item, index) => {return(<Card key={index}>
          <Card.Body>
            <Text style={{fontSize: 26}}>{item["SubjectShort"]}</Text>
            <Text>{item["ActivityName"]}</Text>
            <Text>{item["Start"]+" - "+item["Finish"]}</Text>
            {renderIf(item["OldLocation"] !== "")(
              <Text style={{textDecorationLine: "line-through"}}>{item["OldLocation"]}</Text>
            )}
            <Text>{item["Location"]}</Text>
            <Text style={{textDecorationLine: item["CoveringManager"] !== "" ? "line-through" : "none"}}>{item["OriginalManager"]}</Text>
            {renderIf(item["CoveringManager"] !== "")(
              <Text>{item["CoveringManager"]}</Text>
            )}
          </Card.Body>
        </Card>)});
    return (
      <View style={{flex: 1}}>
        <ScrollView contentContainerStyle={{flex: this.state.items.length === 0 ? 1 : 0}} refreshControl={
          <RefreshControl refreshing={this.state.refreshing} onRefresh={this.refresh.bind(this)} />
        }>
          <Button text={this.state.date.toDateString()} onPress={() => this.setState({showDatePicker: !this.state.showDatePicker})} />
          {cardArray}
          {renderIf(this.state.items.length === 0)(
            <View style={{flex: 1, justifyContent: "center", alignItems: "center"}}>
              <Text style={{fontSize: 28, textAlign: "center", marginBottom: 10}}>There's nothing on this date.</Text>
              <Text style={{fontSize: 20, textAlign: "center"}}>Pull to check for new classes.</Text>
            </View>
          )}
        </ScrollView>
        {renderIf(this.state.showDatePicker)(
          <DatePickerIOS date={this.state.date} mode="date" onDateChange={this.onDateChange.bind(this)} />
        )}
      </View>
    );
  }
}

class DebugView extends Component {
  logOut() {
    compassAPI.logOut();
    this.props.navigator.push({component: SchoolSelectionView});
  }
  render() {
    return (
      <Button text="Log out" style={{margin: 20}} onPress={() => this.logOut()}>Log out</Button>
    );
  }
}

class LearningTasksView extends Component {
  async refresh() {
    this.setState({
      refreshing: true
    });
    var learningTasks = await compassAPI.learningTasks();
    if (learningTasks) {
      this.setState({
        items: learningTasks,
        refreshing: false
      });
    } else {
      console.log("Could not refresh home feed. Are you logged in?");
    }
  }
  constructor(props, context) {
    super(props, context);
    this.state = {items:[], refreshing: false}
    this.refresh();
  }
  statusColour(dueDateString, student) {
    if (dueDateString !== "") {
      var dueDate = new Date(dueDateString);
      var today = new Date();
      if (dueDate.getTime() - today.getTime() < 0) {
        var overdue = true;
      } else {
        var overdue = false;
      }
    } else {
      var overdue = false;
    }

    var submitted = student["submittedTimestamp"] !== "";
    if (submitted) {
      var submissionDate = new Date(student["submittedTimestamp"]);
      var overdueSubmission = dueDate.getTime() - submissionDate.getTime() < 0;
    }
    if (overdue && !submitted) {
      return "red";
    } else if (overdueSubmission && submitted) {
      return "yellow";
    } else if (!overdue && !submitted) {
      return "lightblue";
    } else if (!overdueSubmission && submitted) {
      return "green";
    }
  }
  render() {
    let cardArray = this.state.items.map((item, index) => {return(<Card key={index}>
          <Card.Body>
            <View style={{flexDirection:"row", flexWrap:"nowrap", alignItems:"center", justifyContent:"center", marginBottom: 10}}>
            <Text style={{fontSize: 26, flex:1}}>{item["name"]}</Text>
            <View style={{width:36, height:36, borderRadius: 18, backgroundColor: this.statusColour(item["dueDateTimestamp"], item["students"][0])}} />
            </View>
            <Text>{item["activityName"]}</Text>
          </Card.Body>
        </Card>)});
    return (
      <ScrollView contentContainerStyle={{flex: this.state.items.length === 0 ? 1 : 0}} refreshControl={
        <RefreshControl refreshing={this.state.refreshing} onRefresh={this.refresh.bind(this)} />
      }>
        {cardArray}
        {renderIf(this.state.items.length === 0)(
          <View style={{flex: 1, justifyContent: "center", alignItems: "center"}}>
            <Text style={{fontSize: 28, textAlign: "center", marginBottom: 10}}>No learning tasks.</Text>
            <Text style={{fontSize: 20, textAlign: "center"}}>Pull to check for new learning tasks.</Text>
          </View>
        )}
      </ScrollView>
    );
  }
}

class MainTabbedView extends Component {
  async checkCompassApi() {
    var apiKey = await compassAPI.retrieveSettings();
    if (!apiKey) {
      this.props.navigator.push({component: SchoolSelectionView, props: {mainView: this}});
    }
  }
  refresh() {
    this.refs.newsView.refresh();
    this.refs.scheduleView.refresh();
    this.refs.learningTasksView.refresh();
  }
  constructor(props, context) {
    super(props, context);
    this.checkCompassApi();
  }
  static navigationDelegate = {
    id: "tabbedViewScene",
    renderTitle(props) {
      return <Text style={{fontSize: 18, color: "#ffffff"}}>North</Text>
    }
  }
  render() {
    return (
      <YANavigator.Scene delegate={this} style={styles.container}>
        <ScrollableTabView tabBarBackgroundColor="#fefefe" tabBarUnderlineColor="lightblue" tabBarActiveTextColor="#000" tabBarInactiveTextColor="#aaa" tabBarPosition="bottom" renderTabBar={() => <IconTabBar drawTopBorder="true" />} >
          <NewsView ref="newsView" tabLabel="ios-paper" {...this.props} />
          <ScheduleView ref="scheduleView" tabLabel="ios-clock" {...this.props} />
          <LearningTasksView ref="learningTasksView" tabLabel="md-create" {...this.props} />
          <DebugView ref="debugView" tabLabel="md-help" {...this.props} />
        </ScrollableTabView>
      </YANavigator.Scene>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#FFFFFF',
  },
  loginHUDContainer: {
    flex: 1,
    position:"absolute",
    left: 0,
    top: 0,
    bottom: 0,
    right: 0,
    justifyContent: "center",
    alignItems:"center"
  },
  loginHUD: {
    backgroundColor:"#222",
    borderRadius: 12,
    width: 220,
    height: 120,
    justifyContent: "center",
    alignItems: "center",
  },
  title: {
    marginTop: 20,
    fontSize: 24,
    textAlign: "center"
  },
  row: {
    margin:15,
    fontSize: 16,
    textAlign: "center",
    justifyContent: "center"
  }
});

export default MainTabbedView;<commit_msg>Moved initial refresh to component mounting point<commit_after>"use strict";
import React, { Component } from "react";
import {
  StyleSheet,
  Text,
  View,
  TextInput,
  ListView,
  RecyclerViewBackedScrollView,
  TouchableHighlight,
  Alert,
  RefreshControl,
  Image,
  ScrollView,
  DatePickerIOS
} from "react-native";
import YANavigator from 'react-native-ya-navigator';
import { CompassAPI } from "./compass_api";
import { SchoolSelectionView } from "./login_ui";
const compassAPI = new CompassAPI();
var ScrollableTabView = require("react-native-scrollable-tab-view");
import { Button, Card } from 'react-native-material-design';
import renderIf from "render-if";
import IconTabBar from "./icon_tab_bar";

class NewsView extends Component {
  async refresh() {
    this.setState({
      refreshing: true
    });
    var homeFeed = await compassAPI.homeContent();
    if (homeFeed) {
      var newsItems = homeFeed["news"];
      this.setState({
        items: newsItems,
        refreshing: false
      });
    } else {
      console.log("Could not refresh home feed. Are you logged in?");
    }
  }
  constructor(props, context) {
    super(props, context);
    this.state = {items:[], refreshing: false};
  }
  componentDidMount() {
    this.refresh();
  }
  render() {
    let cardArray = this.state.items.map((item, index) => {return(<Card key={index}>
          <Card.Body>
            <View style={{flexDirection:"row", flexWrap:"nowrap", alignItems:"center", justifyContent:"center", marginBottom: 10}}>
            <Text style={{fontSize: 26, flex:1}}>{item["UploadedBy"]}</Text>
            <Image source={{uri: "https://"+compassAPI.compassURL+item["UserImageUrl"]}} style={{width:76, height:76, borderRadius: 38}} />
            </View>
            <Text>{item["Content"]}</Text>
          </Card.Body>
        </Card>)});
    return (
      <ScrollView contentContainerStyle={{flex: this.state.items.length === 0 ? 1 : 0}} refreshControl={
        <RefreshControl refreshing={this.state.refreshing} onRefresh={this.refresh.bind(this)} />
      }>
        {cardArray}
        {renderIf(this.state.items.length === 0)(
          <View style={{flex: 1, justifyContent: "center", alignItems: "center"}}>
            <Text style={{fontSize: 28, textAlign: "center", marginBottom: 10}}>No news items.</Text>
            <Text style={{fontSize: 20, textAlign: "center"}}>Pull to check for new items.</Text>
          </View>
        )}
      </ScrollView>
    );
  }
}

class ScheduleView extends Component {
  async refresh() {
    this.setState({
      refreshing: true
    });
    var schedule = await compassAPI.scheduleForDate(this.state.date.toISOString().substring(0,10));
    if (schedule) {
      this.setState({
        items: schedule,
        refreshing: false
      });
    } else {
      console.log("Could not refresh today's schedule. Are you logged in?");
    }
  }
  constructor(props, context) {
    super(props, context);
    this.state = {items:[], refreshing: false, date: new Date(), showDatePicker: false};
  }
  componentDidMount() {
    this.refresh();
  }
  async onDateChange(date) {
    await this.setState({date: date});
    this.refresh();
  }
  render() {
    let cardArray = this.state.items.map((item, index) => {return(<Card key={index}>
          <Card.Body>
            <Text style={{fontSize: 26}}>{item["SubjectShort"]}</Text>
            <Text>{item["ActivityName"]}</Text>
            <Text>{item["Start"]+" - "+item["Finish"]}</Text>
            {renderIf(item["OldLocation"] !== "")(
              <Text style={{textDecorationLine: "line-through"}}>{item["OldLocation"]}</Text>
            )}
            <Text>{item["Location"]}</Text>
            <Text style={{textDecorationLine: item["CoveringManager"] !== "" ? "line-through" : "none"}}>{item["OriginalManager"]}</Text>
            {renderIf(item["CoveringManager"] !== "")(
              <Text>{item["CoveringManager"]}</Text>
            )}
          </Card.Body>
        </Card>)});
    return (
      <View style={{flex: 1}}>
        <ScrollView contentContainerStyle={{flex: this.state.items.length === 0 ? 1 : 0}} refreshControl={
          <RefreshControl refreshing={this.state.refreshing} onRefresh={this.refresh.bind(this)} />
        }>
          <Button text={this.state.date.toDateString()} onPress={() => this.setState({showDatePicker: !this.state.showDatePicker})} />
          {cardArray}
          {renderIf(this.state.items.length === 0)(
            <View style={{flex: 1, justifyContent: "center", alignItems: "center"}}>
              <Text style={{fontSize: 28, textAlign: "center", marginBottom: 10}}>There's nothing on this date.</Text>
              <Text style={{fontSize: 20, textAlign: "center"}}>Pull to check for new classes.</Text>
            </View>
          )}
        </ScrollView>
        {renderIf(this.state.showDatePicker)(
          <DatePickerIOS date={this.state.date} mode="date" onDateChange={this.onDateChange.bind(this)} />
        )}
      </View>
    );
  }
}

class DebugView extends Component {
  logOut() {
    compassAPI.logOut();
    this.props.navigator.push({component: SchoolSelectionView});
  }
  render() {
    return (
      <Button text="Log out" style={{margin: 20}} onPress={() => this.logOut()}>Log out</Button>
    );
  }
}

class LearningTasksView extends Component {
  async refresh() {
    this.setState({
      refreshing: true
    });
    var learningTasks = await compassAPI.learningTasks();
    if (learningTasks) {
      this.setState({
        items: learningTasks,
        refreshing: false
      });
    } else {
      console.log("Could not refresh home feed. Are you logged in?");
    }
  }
  constructor(props, context) {
    super(props, context);
    this.state = {items:[], refreshing: false};
  }
  componentDidMount() {
    this.refresh();
  }
  statusColour(dueDateString, student) {
    if (dueDateString !== "") {
      var dueDate = new Date(dueDateString);
      var today = new Date();
      if (dueDate.getTime() - today.getTime() < 0) {
        var overdue = true;
      } else {
        var overdue = false;
      }
    } else {
      var overdue = false;
    }

    var submitted = student["submittedTimestamp"] !== "";
    if (submitted) {
      var submissionDate = new Date(student["submittedTimestamp"]);
      var overdueSubmission = dueDate.getTime() - submissionDate.getTime() < 0;
    }
    if (overdue && !submitted) {
      return "red";
    } else if (overdueSubmission && submitted) {
      return "yellow";
    } else if (!overdue && !submitted) {
      return "lightblue";
    } else if (!overdueSubmission && submitted) {
      return "green";
    }
  }
  render() {
    let cardArray = this.state.items.map((item, index) => {return(<Card key={index}>
          <Card.Body>
            <View style={{flexDirection:"row", flexWrap:"nowrap", alignItems:"center", justifyContent:"center", marginBottom: 10}}>
            <Text style={{fontSize: 26, flex:1}}>{item["name"]}</Text>
            <View style={{width:36, height:36, borderRadius: 18, backgroundColor: this.statusColour(item["dueDateTimestamp"], item["students"][0])}} />
            </View>
            <Text>{item["activityName"]}</Text>
          </Card.Body>
        </Card>)});
    return (
      <ScrollView contentContainerStyle={{flex: this.state.items.length === 0 ? 1 : 0}} refreshControl={
        <RefreshControl refreshing={this.state.refreshing} onRefresh={this.refresh.bind(this)} />
      }>
        {cardArray}
        {renderIf(this.state.items.length === 0)(
          <View style={{flex: 1, justifyContent: "center", alignItems: "center"}}>
            <Text style={{fontSize: 28, textAlign: "center", marginBottom: 10}}>No learning tasks.</Text>
            <Text style={{fontSize: 20, textAlign: "center"}}>Pull to check for new learning tasks.</Text>
          </View>
        )}
      </ScrollView>
    );
  }
}

class MainTabbedView extends Component {
  async checkCompassApi() {
    var apiKey = await compassAPI.retrieveSettings();
    if (!apiKey) {
      this.props.navigator.push({component: SchoolSelectionView, props: {mainView: this}});
    }
  }
  refresh() {
    this.refs.newsView.refresh();
    this.refs.scheduleView.refresh();
    this.refs.learningTasksView.refresh();
  }
  constructor(props, context) {
    super(props, context);
    this.checkCompassApi();
  }
  static navigationDelegate = {
    id: "tabbedViewScene",
    renderTitle(props) {
      return <Text style={{fontSize: 18, color: "#ffffff"}}>North</Text>
    }
  }
  render() {
    return (
      <YANavigator.Scene delegate={this} style={styles.container}>
        <ScrollableTabView tabBarBackgroundColor="#fefefe" tabBarUnderlineColor="lightblue" tabBarActiveTextColor="#000" tabBarInactiveTextColor="#aaa" tabBarPosition="bottom" renderTabBar={() => <IconTabBar drawTopBorder="true" />} >
          <NewsView ref="newsView" tabLabel="ios-paper" {...this.props} />
          <ScheduleView ref="scheduleView" tabLabel="ios-clock" {...this.props} />
          <LearningTasksView ref="learningTasksView" tabLabel="md-create" {...this.props} />
          <DebugView ref="debugView" tabLabel="md-help" {...this.props} />
        </ScrollableTabView>
      </YANavigator.Scene>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#FFFFFF',
  },
  loginHUDContainer: {
    flex: 1,
    position:"absolute",
    left: 0,
    top: 0,
    bottom: 0,
    right: 0,
    justifyContent: "center",
    alignItems:"center"
  },
  loginHUD: {
    backgroundColor:"#222",
    borderRadius: 12,
    width: 220,
    height: 120,
    justifyContent: "center",
    alignItems: "center",
  },
  title: {
    marginTop: 20,
    fontSize: 24,
    textAlign: "center"
  },
  row: {
    margin:15,
    fontSize: 16,
    textAlign: "center",
    justifyContent: "center"
  }
});

export default MainTabbedView;<|endoftext|>


<commit_before>"use strict";

const Constants = require("../../../Constants");
const Events = Constants.Events;

module.exports = function handler(data, gw) {
  if (this.User.id != data.user.id) {
    this.Dispatcher.emit(Events.PRESENCE_UPDATE, {
      socket: gw,
      user: this.Users.get(data.user.id)
    });
  }
  return true;
};
<commit_msg>Add guild to PRESENCE_UPDATE event<commit_after>"use strict";

const Constants = require("../../../Constants");
const Events = Constants.Events;

module.exports = function handler(data, gw) {
  if (this.User.id != data.user.id) {
    this.Dispatcher.emit(Events.PRESENCE_UPDATE, {
      socket: gw,
      guild: this.Guilds.get(data.guild_id),
      user: this.Users.get(data.user.id)
    });
  }
  return true;
};
<|endoftext|>


<commit_before>const path = require("path");
// eslint-disable-next-line node/no-unpublished-require
const CLI = require("../../../packages/webpack-cli/lib/webpack-cli");

const utilsDirectory = {
  cli: "../../../packages/webpack-cli/lib/utils",
  generators: "../../../packages/generators/src/utils",
};

jest.mock(path.join(utilsDirectory.generators, "scaffold-utils"), () => ({
  List: jest.fn(),
}));

const { getInstaller, getTemplate } = require(path.join(utilsDirectory.generators, "helpers"));
const { List } = require(path.join(utilsDirectory.generators, "scaffold-utils"));

describe("helpers", () => {
  let cli;
  let getDefaultPackageManagerSpy;
  let context;

  beforeEach(() => {
    cli = new CLI();
    context = {
      prompt: () => {},
      supportedTemplates: ["default"],
      cli: cli,
    };
    getDefaultPackageManagerSpy = jest.spyOn(cli, "getDefaultPackageManager");
  });

  afterEach(() => {
    jest.clearAllMocks();

    getDefaultPackageManagerSpy.mockRestore();
  });

  it("getInstaller() returns the available installer", async () => {
    // Multiple installers are not available
    getDefaultPackageManagerSpy.mockReturnValue(["npm"]);

    // User chose "pnpm"
    List.mockReturnValue({ packager: "npm" });

    // Invoke the helper function
    const installer = await getInstaller.call(context);

    expect(installer).toBe("npm");
  });

  it("getInstaller() invokes a List prompt if multiple installers are available", async () => {
    // Multiple installers are available
    getDefaultPackageManagerSpy.mockReturnValue(["npm", "yarn", "pnpm"]);

    // User chose "pnpm"
    List.mockReturnValue({ packager: "pnpm" });

    // Invoke the helper function
    const installer = await getInstaller.call(context);
    expect(installer).toBe("pnpm");
  });

  it("getTemplate() returns with the valid template", async () => {
    context.template = "default";

    // Invoke the helper function
    const template = await getTemplate.call(context);

    expect(template).toBe("default");
  });

  it("getTemplate() invokes a List prompt on supplying an invalid template", async () => {
    context.template = "unknown";

    // User chose "default"
    List.mockReturnValue({ selectedTemplate: "default" });

    const { logger } = cli;
    const loggerMock = jest.spyOn(logger, "warn").mockImplementation(() => {});
    // Invoke the helper function`
    const template = await getTemplate.call(context);

    expect(template).toBe("default");
    expect(loggerMock).toHaveBeenCalled();
  });
});
<commit_msg>test: add test for helpers (#3325)<commit_after>const path = require("path");
// eslint-disable-next-line node/no-unpublished-require
const CLI = require("../../../packages/webpack-cli/lib/webpack-cli");

const utilsDirectory = {
  cli: "../../../packages/webpack-cli/lib/utils",
  generators: "../../../packages/generators/src/utils",
};

jest.mock(path.join(utilsDirectory.generators, "scaffold-utils"), () => ({
  List: jest.fn(),
}));

const { getInstaller, getTemplate, toKebabCase, toUpperCamelCase } = require(path.join(
  utilsDirectory.generators,
  "helpers",
));
const { List } = require(path.join(utilsDirectory.generators, "scaffold-utils"));

describe("helpers", () => {
  let cli;
  let getDefaultPackageManagerSpy;
  let context;

  beforeEach(() => {
    cli = new CLI();
    context = {
      prompt: () => {},
      supportedTemplates: ["default"],
      cli: cli,
    };
    getDefaultPackageManagerSpy = jest.spyOn(cli, "getDefaultPackageManager");
  });

  afterEach(() => {
    jest.clearAllMocks();

    getDefaultPackageManagerSpy.mockRestore();
  });

  it("toKebabCase() returns kebab case", () => {
    const kebabValue = toKebabCase("HtmlMinimizerPlugin");

    expect(kebabValue).toBe("html-minimizer-plugin");
  });

  it("toUpperCamelCase() returns camel case strings", () => {
    const camelCaseString = toUpperCamelCase("html-minimizer-webpack-plugin");

    expect(camelCaseString).toBe("HtmlMinimizerWebpackPlugin");
  });

  it("getInstaller() returns the available installer", async () => {
    // Multiple installers are not available
    getDefaultPackageManagerSpy.mockReturnValue(["npm"]);

    // User chose "pnpm"
    List.mockReturnValue({ packager: "npm" });

    // Invoke the helper function
    const installer = await getInstaller.call(context);

    expect(installer).toBe("npm");
  });

  it("getInstaller() invokes a List prompt if multiple installers are available", async () => {
    // Multiple installers are available
    getDefaultPackageManagerSpy.mockReturnValue(["npm", "yarn", "pnpm"]);

    // User chose "pnpm"
    List.mockReturnValue({ packager: "pnpm" });

    // Invoke the helper function
    const installer = await getInstaller.call(context);
    expect(installer).toBe("pnpm");
  });

  it("getTemplate() returns with the valid template", async () => {
    context.template = "default";

    // Invoke the helper function
    const template = await getTemplate.call(context);

    expect(template).toBe("default");
  });

  it("getTemplate() invokes a List prompt on supplying an invalid template", async () => {
    context.template = "unknown";

    // User chose "default"
    List.mockReturnValue({ selectedTemplate: "default" });

    const { logger } = cli;
    const loggerMock = jest.spyOn(logger, "warn").mockImplementation(() => {});
    // Invoke the helper function`
    const template = await getTemplate.call(context);

    expect(template).toBe("default");
    expect(loggerMock).toHaveBeenCalled();
  });
});
<|endoftext|>