Source: maxflow-push-relabel/js/ResidualEdge.js

/**
 * @classdesc
 * Represents a residual edge in the residual Graph  G'
 * @constructor
 */
Graph.ResidualEdge = function(idOrObj, forward) {
  if(idOrObj && forward==null){ //from json.stringify
    this.id = idOrObj.id;
    this.forward = idOrObj.forward;
  }else{ //2 args constructor
    this.id = idOrObj;
    this.forward = forward;
  }
}

/**
 * The original edge of the graph G
 */
Graph.ResidualEdge.prototype.edge = function(){
  return Graph.instance.edges.get(this.id);
}

/**
 * The residual capacity
 */
Graph.ResidualEdge.prototype.c_dash = function(){
  var edge = this.edge();
  if (this.forward) {
      return edge.resources[0] - edge.state.flow;
  } else {
      return edge.state.flow;
  }
}

Graph.ResidualEdge.prototype.notnull = function(){
  var c = this.c_dash();
  return c > 0;
}

/**
 * The start vertex
 */
Graph.ResidualEdge.prototype.start = function(){
  var edge = this.edge();
  if(this.forward){
    return edge.start;
  }else{
    return edge.end;
  }
}

/**
 * The end vertex
 */
Graph.ResidualEdge.prototype.end = function(){
  var edge = this.edge();
  if(this.forward){
    return edge.end;
  }else{
    return edge.start;
  }
}

Graph.ResidualEdge.prototype.legal = function(){
  return this.start().state.height == this.end().state.height + 1 
}

Graph.ResidualEdge.prototype.increaseFlow = function(delta){
  var edge = this.edge();
  if (this.forward) {
      edge.state.flow += delta;
  } else {
      edge.state.flow -= delta;
  }
}

Graph.ResidualEdge.prototype.toString = function() {
  return (this.forward ? "forward " : "backward ") + "residual edge e'=("+this.start().id + "," + this.end().id + ") with c'=" + this.c_dash();
}

//not necessarily legal, forward star of node in G'
Graph.Node.prototype.getAllOutgoingResidualEdges = function(unfiltered) {
  var e_dashes = [];

  /*forward edges*/
  this.outEdges.forEach(function(key, edge) {
      e_dashes.push(new Graph.ResidualEdge(key, true));
  });

  /*backward edges*/
  this.inEdges.forEach(function(key, edge) {
      e_dashes.push(new Graph.ResidualEdge(key, false));
  });

  if(unfiltered) return e_dashes;

  //If capacity == 0, we don't speak of an residual edge anymore
  var filteredEdges = e_dashes.filter(function(e_dash) {
      return e_dash.notnull();
  });

  return filteredEdges;
}

//function getLegalResidualEdge(node) {
Graph.Node.prototype.getLegalResidualEdge = function(node){

  var arrEdges = [this.outEdges.keys(),this.inEdges.keys()];
  var arrForward = [true,false];

  for(var i=0; i<2; i++){
    var ids = arrEdges[i];
    for(var j=0; j<ids.length; j++){
      var id = ids[j];
      var e_dash = new Graph.ResidualEdge(id, arrForward[i]);
      if(e_dash.notnull() && e_dash.legal()){
        return e_dash;
      }
    }
  }
  
  return null;
}