<commit_before>var matrix = exports;

/**
 * Return a deep copy of the input matrix.
 *
 * @param {Array} matrix to copy.
 * @return {Array} copied matrix.
 */
matrix.deepCopy = function(arr) {
    if(arr[0][0] === undefined) {
        throw new Error("Input cannot be a vector.");
    }
    var result = new Array(arr.length);

    for(var i = 0; i < arr.length; i++) {
        result[i] = arr[i].slice();
    }
    return result;
};

/**
 * Return true if matrix is square, false otherwise.
 *
 * @param {Array} arr
 */
matrix.isSquare = function(arr) {
    var rows = arr.length;
    var cols = arr[0].length;
    return rows === cols;
};

/**
 * Add two matrices together.  Matrices must be of same dimension.
 *
 * @param {Array} matrix A.
 * @param {Array} matrix B.
 * @return {Array} summed matrix.
 */
matrix.addition = function (arrA, arrB) {
  if ((arrA.length === arrB.length) && (arrA[0].length === arrB[0].length)) {
    var result = new Array(arrA.length);

    for (var i = 0; i < arrA.length; i++) {
      result[i] = new Array(arrA[i].length);

      for (var j = 0; j < arrA[i].length; j++) {
        result[i][j] = arrA[i][j] + arrB[i][j];
      }
    }

    return result;
  } else {
    throw new Error('Matrix mismatch');
  }
};

/**
 * Scalar multiplication on an matrix.
 *
 * @param {Array} matrix.
 * @param {Number} scalar.
 * @return {Array} updated matrix.
 */
matrix.scalar = function (arr, val) {
  for (var i = 0; i < arr.length; i++) {
    for (var j = 0; j < arr[i].length; j++) {
      arr[i][j] = val * arr[i][j];
    }
  }

  return arr;
};

/**
 * Transpose a matrix.
 *
 * @param {Array} matrix.
 * @return {Array} transposed matrix.
 */
matrix.transpose = function (arr) {
  var result = new Array(arr[0].length);

  for (var i = 0; i < arr[0].length; i++) {
    result[i] = new Array(arr.length);

    for (var j = 0; j < arr.length; j++) {
      result[i][j] = arr[j][i];
    }
  }

  return result;
};

/**
 * Create an identity matrix of dimension n x n.
 *
 * @param {Number} dimension of the identity array to be returned.
 * @return {Array} n x n identity matrix.
 */
matrix.identity = function (n) {
  var result = new Array(n);
  for (var i = 0; i < n ; i++) {
    result[i] = new Array(n);
    for (var j = 0; j < n; j++) {
      result[i][j] = (i === j) ? 1 : 0;
    }
  }

  return result;
};

/**
 * Evaluate dot product of two vectors.  Vectors must be of same length.
 *
 * @param {Array} vector.
 * @param {Array} vector.
 * @return {Array} dot product.
 */
matrix.dotproduct = function (vectorA, vectorB) {
  if (vectorA.length === vectorB.length) {
    var result = 0;
    for (var i = 0; i < vectorA.length; i++) {
      result += vectorA[i] * vectorB[i];
    }
    return result;
  } else {
    throw new Error("Vector mismatch");
  }
};

/**
 * Multiply two matrices. They must abide by standard matching.
 *
 * e.g. A x B = (m x n) x (n x m), where n, m are integers who define
 * the dimensions of matrices A, B.
 *
 * @param {Array} matrix.
 * @param {Array} matrix.
 * @return {Array} result of multiplied matrices.
 */
matrix.multiply = function (arrA, arrB) {
  if (arrA[0].length === arrB.length) {
    var result = new Array(arrA.length);

    for (var x = 0; x < arrA.length; x++) {
      result[x] = new Array(arrB[0].length);
    }

    var arrB_T = matrix.transpose(arrB);

    for (var i = 0; i < result.length; i++) {
      for (var j = 0; j < result[i].length; j++) {
        result[i][j] = matrix.dotproduct(arrA[i],arrB_T[j]);
      }
    }
    return result;
  } else {
    throw new Error("Array mismatch");
  }
};

/**
 * Evaluate determinate of matrix.  Expect speed
 * degradation for matrices over 4x4.
 *
 * @param {Array} matrix.
 * @return {Number} determinant.
 */
matrix.determinant = function (m) {
  var numRow = m.length;
  var numCol = m[0].length;
  var det = 0;
  var row, col;
  var diagLeft, diagRight;

  if (numRow !== numCol) {
    throw new Error("Not a square matrix.")
  }

  if (numRow === 1) {
    return m[0][0];
  }
  else if (numRow === 2) {
    return m[0][0] * m[1][1] - m[0][1] * m[1][0];
  }

  for (col = 0; col < numCol; col++) {
    diagLeft = m[0][col];
    diagRight = m[0][col];

    for( row=1; row < numRow; row++ ) {
      diagRight *= m[row][(((col + row) % numCol) + numCol) % numCol];
      diagLeft *= m[row][(((col - row) % numCol) + numCol) % numCol];
    }

    det += diagRight - diagLeft;
  }

  return det;
};

/**
 * Returns a LUP decomposition of the given matrix such that:
 *
 * A*P = L*U
 *
 * Where
 * A is the input matrix
 * P is a pivot matrix
 * L is a lower triangular matrix
 * U is a upper triangular matrix
 *
 * This method returns an array of three matrices such that:
 *
 * matrix.luDecomposition(array) = [L, U, P]
 *
 * @param {Array} arr
 * @return {Array} array of matrices [L, U, P]
 */
matrix.lupDecomposition = function(arr) {
    if (!matrix.isSquare(arr)) {
        throw new Error("Matrix must be square.");
    }

    var size = arr.length;

    var LU = matrix.deepCopy(arr);
    var P = matrix.transpose(matrix.identity(size));
    var currentRow;
    var currentColumn = new Array(size);

    this.swapRows = function(m, firstRowIndex, secondRowIndex) {
        var temp = m[firstRowIndex];
        m[firstRowIndex] = m[secondRowIndex];
        m[secondRowIndex] = temp;
    };

    this.getL = function(a) {
        var m = a[0].length;
        var L = matrix.identity(m);
        for (var i = 0; i < m; i++) {
            for (var j = 0; j < m; j++) {
                if (i > j) {
                    L[i][j] = a[i][j];
                } else if (i == j) {
                    L[i][j] = 1.0;
                } else {
                    L[i][j] = 0.0;
                }
            }
        }
        return L;
    };

    this.getU =function(a) {
        var m = a[0].length;
        var U = matrix.identity(m);
        for (var i = 0; i < m; i++) {
            for (var j = 0; j < m; j++) {
                if (i <= j) {
                    U[i][j] = a[i][j];
                } else {
                    U[i][j] = 0.0;
                }
            }
        }
        return U;
    };

    for (var j = 0; j < size; j++) {
        for (var i = 0; i < size; i++) {
            currentColumn[i] = LU[i][j];
        }

        for (var i = 0; i < size; i++) {
            currentRow = LU[i];

            var minIndex = Math.min(i,j);
            var s = 0;
            for (var k = 0; k < minIndex; k++) {
                s += currentRow[k]*currentColumn[k];
            }

            currentRow[j] = currentColumn[i] -= s;
        }

        //Find pivot
        var pivot = j;
        for (var i = j+1; i < size; i++) {
            if (Math.abs(currentColumn[i]) > Math.abs(currentColumn[pivot])) {
                pivot = i;
            }
        }
        if (pivot != j) {
            this.swapRows(LU, pivot, j);
            this.swapRows(P, pivot, j);
        }

        if (j < size && LU[j][j] != 0) {
            for (var i = j+1; i < size; i++) {
                LU[i][j] /= LU[j][j];
            }
        }
    }
    return [this.getL(LU), this.getU(LU), P];
};

/**
 * Rotate a two dimensional vector by degree.
 *
 * @param {Array} point.
 * @param {Number} degree.
 * @param {String} direction - clockwise or counterclockwise.
 * @return {Array} vector.
 */
matrix.rotate = function (point, degree, direction) {
  if (point.length === 2) {
    var negate = direction === 'clockwise' ? -1 : 1;
    var radians = degree * (Math.PI / 180);

    var transformation = [
      [Math.cos(radians), -1 * negate * Math.sin(radians)],
      [negate * Math.sin(radians), Math.cos(radians)]
    ];

    return matrix.multiply(transformation, point);
  } else {
    throw new Error('Only two dimensional operations are supported at this time');
  }
};

/**
 * Scale a two dimensional vector by scale factor x and scale factor y.
 *
 * @param {Array} point.
 * @param {Number} sx.
 * @param {Number} sy.
 * @return {Array} vector.
 */
matrix.scale = function (point, sx, sy) {
  if (point.length === 2) {

    var transformation = [
      [sx, 0],
      [0, sy]
    ];

    return matrix.multiply(transformation, point);
  } else {
    throw new Error('Only two dimensional operations are supported at this time');
  }
};

/**
 * Shear a two dimensional vector by shear factor k.
 *
 * @param {Array} point.
 * @param {Number} k.
 * @param {String} direction - xaxis or yaxis.
 * @return {Array} vector.
 */
matrix.shear = function (point, k, direction) {
  if (point.length === 2) {
    var xplaceholder = direction === 'xaxis' ? k : 0;
    var yplaceholder = direction === 'yaxis' ? k : 0;

    var transformation = [
      [1, xplaceholder],
      [yplaceholder, 1]
    ];

    return matrix.multiply(transformation, point);
  } else {
    throw new Error('Only two dimensional operations are supported at this time');
  }
};

/**
 * Perform an affine transformation on the given vector.
 *
 * @param {Array} point.
 * @param {Number} tx.
 * @param {Number} ty.
 * @return {Array} vector.
 */
matrix.affine = function (point, tx, ty) {
  if (point.length === 2) {

    var transformation = [
      [1, 0, tx],
      [0, 1, ty],
      [0, 0, 1 ]
    ];

    var newpoint = [
      [point[0][0]],
      [point[1][0]],
      [1]
    ];

    var transformed = matrix.multiply(transformation, newpoint);

    return [
      [transformed[0][0]],
      [transformed[1][0]]
    ];

  } else {
    throw new Error('Only two dimensional operations are supported at this time');
  }
};

/**
 * Scales a row of a matrix by a factor and returns the updated matrix.
 * Used in row reduction functions.
 *
 * @param {Array} matrix.
 * @param {Number} row.
 * @param {Number} scale.
 */
matrix.rowScale = function (m, row, scale) {
  var result = new Array(m.length);

  for (var i = 0; i < m.length; i++) {
    result[i] = new Array(m[i].length);

    for (var j = 0; j < m[i].length; j++) {
      if (i === row) {
        result[i][j] = scale * m[i][j];
      } else {
        result[i][j] = m[i][j];
      }
    }
  }

  return result;
};

/**
 * Swaps two rows of a matrix  and returns the updated matrix.
 * Used in row reduction functions.
 *
 * @param {Array} matrix.
 * @param {Number} row1.
 * @param {Number} row2.
 */
matrix.rowSwitch = function (m, row1, row2) {
  var result = new Array(m.length);

  for (var i = 0; i < m.length; i++) {
    result[i] = new Array(m[i].length);

    for (var j = 0; j < m[i].length; j++) {
      if (i === row1) {
        result[i][j] = m[row2][j];
      } else if (i === row2) {
        result[i][j] = m[row1][j];
      } else {
        result[i][j] = m[i][j];
      }
    }
  }
  return result;
};

/**
 * Adds a multiple of one row to another row
 * in a matrix and returns the updated matrix.
 * Used in row reduction functions.
 *
 * @param {Array} matrix.
 * @param {Number} row1.
 * @param {Number} row2.
 */
matrix.rowAddMultiple = function (m, from, to, scale){
  var result = new Array(m.length);

  for (var i = 0; i < m.length; i++) {
    result[i] = new Array(m[i].length);

    for (var j = 0; j < m[i].length; j++) {
      if (i === to) {
        result[to][j] = m[to][j] + scale * m[from][j];
      } else {
        result[i][j] = m[i][j];
      }
    }
  }

  return result;
};
<commit_msg>remove custom swap function - one already existed.<commit_after>var matrix = exports;

/**
 * Return a deep copy of the input matrix.
 *
 * @param {Array} matrix to copy.
 * @return {Array} copied matrix.
 */
matrix.deepCopy = function(arr) {
    if(arr[0][0] === undefined) {
        throw new Error("Input cannot be a vector.");
    }
    var result = new Array(arr.length);

    for(var i = 0; i < arr.length; i++) {
        result[i] = arr[i].slice();
    }
    return result;
};

/**
 * Return true if matrix is square, false otherwise.
 *
 * @param {Array} arr
 */
matrix.isSquare = function(arr) {
    var rows = arr.length;
    var cols = arr[0].length;
    return rows === cols;
};

/**
 * Add two matrices together.  Matrices must be of same dimension.
 *
 * @param {Array} matrix A.
 * @param {Array} matrix B.
 * @return {Array} summed matrix.
 */
matrix.addition = function (arrA, arrB) {
  if ((arrA.length === arrB.length) && (arrA[0].length === arrB[0].length)) {
    var result = new Array(arrA.length);

    for (var i = 0; i < arrA.length; i++) {
      result[i] = new Array(arrA[i].length);

      for (var j = 0; j < arrA[i].length; j++) {
        result[i][j] = arrA[i][j] + arrB[i][j];
      }
    }

    return result;
  } else {
    throw new Error('Matrix mismatch');
  }
};

/**
 * Scalar multiplication on an matrix.
 *
 * @param {Array} matrix.
 * @param {Number} scalar.
 * @return {Array} updated matrix.
 */
matrix.scalar = function (arr, val) {
  for (var i = 0; i < arr.length; i++) {
    for (var j = 0; j < arr[i].length; j++) {
      arr[i][j] = val * arr[i][j];
    }
  }

  return arr;
};

/**
 * Transpose a matrix.
 *
 * @param {Array} matrix.
 * @return {Array} transposed matrix.
 */
matrix.transpose = function (arr) {
  var result = new Array(arr[0].length);

  for (var i = 0; i < arr[0].length; i++) {
    result[i] = new Array(arr.length);

    for (var j = 0; j < arr.length; j++) {
      result[i][j] = arr[j][i];
    }
  }

  return result;
};

/**
 * Create an identity matrix of dimension n x n.
 *
 * @param {Number} dimension of the identity array to be returned.
 * @return {Array} n x n identity matrix.
 */
matrix.identity = function (n) {
  var result = new Array(n);
  for (var i = 0; i < n ; i++) {
    result[i] = new Array(n);
    for (var j = 0; j < n; j++) {
      result[i][j] = (i === j) ? 1 : 0;
    }
  }

  return result;
};

/**
 * Evaluate dot product of two vectors.  Vectors must be of same length.
 *
 * @param {Array} vector.
 * @param {Array} vector.
 * @return {Array} dot product.
 */
matrix.dotproduct = function (vectorA, vectorB) {
  if (vectorA.length === vectorB.length) {
    var result = 0;
    for (var i = 0; i < vectorA.length; i++) {
      result += vectorA[i] * vectorB[i];
    }
    return result;
  } else {
    throw new Error("Vector mismatch");
  }
};

/**
 * Multiply two matrices. They must abide by standard matching.
 *
 * e.g. A x B = (m x n) x (n x m), where n, m are integers who define
 * the dimensions of matrices A, B.
 *
 * @param {Array} matrix.
 * @param {Array} matrix.
 * @return {Array} result of multiplied matrices.
 */
matrix.multiply = function (arrA, arrB) {
  if (arrA[0].length === arrB.length) {
    var result = new Array(arrA.length);

    for (var x = 0; x < arrA.length; x++) {
      result[x] = new Array(arrB[0].length);
    }

    var arrB_T = matrix.transpose(arrB);

    for (var i = 0; i < result.length; i++) {
      for (var j = 0; j < result[i].length; j++) {
        result[i][j] = matrix.dotproduct(arrA[i],arrB_T[j]);
      }
    }
    return result;
  } else {
    throw new Error("Array mismatch");
  }
};

/**
 * Evaluate determinate of matrix.  Expect speed
 * degradation for matrices over 4x4.
 *
 * @param {Array} matrix.
 * @return {Number} determinant.
 */
matrix.determinant = function (m) {
  var numRow = m.length;
  var numCol = m[0].length;
  var det = 0;
  var row, col;
  var diagLeft, diagRight;

  if (numRow !== numCol) {
    throw new Error("Not a square matrix.")
  }

  if (numRow === 1) {
    return m[0][0];
  }
  else if (numRow === 2) {
    return m[0][0] * m[1][1] - m[0][1] * m[1][0];
  }

  for (col = 0; col < numCol; col++) {
    diagLeft = m[0][col];
    diagRight = m[0][col];

    for( row=1; row < numRow; row++ ) {
      diagRight *= m[row][(((col + row) % numCol) + numCol) % numCol];
      diagLeft *= m[row][(((col - row) % numCol) + numCol) % numCol];
    }

    det += diagRight - diagLeft;
  }

  return det;
};

/**
 * Returns a LUP decomposition of the given matrix such that:
 *
 * A*P = L*U
 *
 * Where
 * A is the input matrix
 * P is a pivot matrix
 * L is a lower triangular matrix
 * U is a upper triangular matrix
 *
 * This method returns an array of three matrices such that:
 *
 * matrix.luDecomposition(array) = [L, U, P]
 *
 * @param {Array} arr
 * @return {Array} array of matrices [L, U, P]
 */
matrix.lupDecomposition = function(arr) {
    if (!matrix.isSquare(arr)) {
        throw new Error("Matrix must be square.");
    }

    var size = arr.length;

    var LU = matrix.deepCopy(arr);
    var P = matrix.transpose(matrix.identity(size));
    var currentRow;
    var currentColumn = new Array(size);

    this.getL = function(a) {
        var m = a[0].length;
        var L = matrix.identity(m);
        for (var i = 0; i < m; i++) {
            for (var j = 0; j < m; j++) {
                if (i > j) {
                    L[i][j] = a[i][j];
                } else if (i == j) {
                    L[i][j] = 1.0;
                } else {
                    L[i][j] = 0.0;
                }
            }
        }
        return L;
    };

    this.getU = function(a) {
        var m = a[0].length;
        var U = matrix.identity(m);
        for (var i = 0; i < m; i++) {
            for (var j = 0; j < m; j++) {
                if (i <= j) {
                    U[i][j] = a[i][j];
                } else {
                    U[i][j] = 0.0;
                }
            }
        }
        return U;
    };

    for (var j = 0; j < size; j++) {
        for (var i = 0; i < size; i++) {
            currentColumn[i] = LU[i][j];
        }

        for (var i = 0; i < size; i++) {
            currentRow = LU[i];

            var minIndex = Math.min(i,j);
            var s = 0;
            for (var k = 0; k < minIndex; k++) {
                s += currentRow[k]*currentColumn[k];
            }

            currentRow[j] = currentColumn[i] -= s;
        }

        //Find pivot
        var pivot = j;
        for (var i = j+1; i < size; i++) {
            if (Math.abs(currentColumn[i]) > Math.abs(currentColumn[pivot])) {
                pivot = i;
            }
        }
        if (pivot != j) {
            LU = matrix.rowSwitch(LU, pivot, j);
            P = matrix.rowSwitch(P, pivot, j);
        }

        if (j < size && LU[j][j] != 0) {
            for (var i = j+1; i < size; i++) {
                LU[i][j] /= LU[j][j];
            }
        }
    }
    return [this.getL(LU), this.getU(LU), P];
};

/**
 * Rotate a two dimensional vector by degree.
 *
 * @param {Array} point.
 * @param {Number} degree.
 * @param {String} direction - clockwise or counterclockwise.
 * @return {Array} vector.
 */
matrix.rotate = function (point, degree, direction) {
  if (point.length === 2) {
    var negate = direction === 'clockwise' ? -1 : 1;
    var radians = degree * (Math.PI / 180);

    var transformation = [
      [Math.cos(radians), -1 * negate * Math.sin(radians)],
      [negate * Math.sin(radians), Math.cos(radians)]
    ];

    return matrix.multiply(transformation, point);
  } else {
    throw new Error('Only two dimensional operations are supported at this time');
  }
};

/**
 * Scale a two dimensional vector by scale factor x and scale factor y.
 *
 * @param {Array} point.
 * @param {Number} sx.
 * @param {Number} sy.
 * @return {Array} vector.
 */
matrix.scale = function (point, sx, sy) {
  if (point.length === 2) {

    var transformation = [
      [sx, 0],
      [0, sy]
    ];

    return matrix.multiply(transformation, point);
  } else {
    throw new Error('Only two dimensional operations are supported at this time');
  }
};

/**
 * Shear a two dimensional vector by shear factor k.
 *
 * @param {Array} point.
 * @param {Number} k.
 * @param {String} direction - xaxis or yaxis.
 * @return {Array} vector.
 */
matrix.shear = function (point, k, direction) {
  if (point.length === 2) {
    var xplaceholder = direction === 'xaxis' ? k : 0;
    var yplaceholder = direction === 'yaxis' ? k : 0;

    var transformation = [
      [1, xplaceholder],
      [yplaceholder, 1]
    ];

    return matrix.multiply(transformation, point);
  } else {
    throw new Error('Only two dimensional operations are supported at this time');
  }
};

/**
 * Perform an affine transformation on the given vector.
 *
 * @param {Array} point.
 * @param {Number} tx.
 * @param {Number} ty.
 * @return {Array} vector.
 */
matrix.affine = function (point, tx, ty) {
  if (point.length === 2) {

    var transformation = [
      [1, 0, tx],
      [0, 1, ty],
      [0, 0, 1 ]
    ];

    var newpoint = [
      [point[0][0]],
      [point[1][0]],
      [1]
    ];

    var transformed = matrix.multiply(transformation, newpoint);

    return [
      [transformed[0][0]],
      [transformed[1][0]]
    ];

  } else {
    throw new Error('Only two dimensional operations are supported at this time');
  }
};

/**
 * Scales a row of a matrix by a factor and returns the updated matrix.
 * Used in row reduction functions.
 *
 * @param {Array} matrix.
 * @param {Number} row.
 * @param {Number} scale.
 */
matrix.rowScale = function (m, row, scale) {
  var result = new Array(m.length);

  for (var i = 0; i < m.length; i++) {
    result[i] = new Array(m[i].length);

    for (var j = 0; j < m[i].length; j++) {
      if (i === row) {
        result[i][j] = scale * m[i][j];
      } else {
        result[i][j] = m[i][j];
      }
    }
  }

  return result;
};

/**
 * Swaps two rows of a matrix  and returns the updated matrix.
 * Used in row reduction functions.
 *
 * @param {Array} matrix.
 * @param {Number} row1.
 * @param {Number} row2.
 */
matrix.rowSwitch = function (m, row1, row2) {
  var result = new Array(m.length);

  for (var i = 0; i < m.length; i++) {
    result[i] = new Array(m[i].length);

    for (var j = 0; j < m[i].length; j++) {
      if (i === row1) {
        result[i][j] = m[row2][j];
      } else if (i === row2) {
        result[i][j] = m[row1][j];
      } else {
        result[i][j] = m[i][j];
      }
    }
  }
  return result;
};

/**
 * Adds a multiple of one row to another row
 * in a matrix and returns the updated matrix.
 * Used in row reduction functions.
 *
 * @param {Array} matrix.
 * @param {Number} row1.
 * @param {Number} row2.
 */
matrix.rowAddMultiple = function (m, from, to, scale){
  var result = new Array(m.length);

  for (var i = 0; i < m.length; i++) {
    result[i] = new Array(m[i].length);

    for (var j = 0; j < m[i].length; j++) {
      if (i === to) {
        result[to][j] = m[to][j] + scale * m[from][j];
      } else {
        result[i][j] = m[i][j];
      }
    }
  }

  return result;
};
<|endoftext|>


<commit_before>'use strict';

var proxyDns = require('./proxy_dns.js'),
	http = require('http'),
	https = require('https'),
	zlib = require('zlib'),
	inject=require('./inject');

var https_url = {};

/**
 * 处理代理响应
 */
function proxyResponse(clientReq, clientRes, serverRes, secure) {
	//console.log(serverRes.statusCode, serverRes.headers);

	//
	// 检测是否重定向到https站点
	//
	if (serverRes.statusCode == 302) {
		var newUrl = serverRes.headers['location'];

		if (newUrl && newUrl.substr(0, 8) == 'https://') {
			var url = newUrl.substr(8);
			https_url[url] = true;

			var pos = newUrl.indexOf('/', 8);
			clientReq.url = newUrl.substr(pos);
			clientReq.headers['host'] = newUrl.substring(8, pos);

			proxyRequest(clientReq, clientRes);
			clientReq.emit('end');

			console.log('[WEB] `%s` goto `%s`',
				clientReq.headers['host'] + clientReq.url,
				newUrl
			);
			return;
		}
	}

	var resHeader = serverRes.headers;

	//
	// 过滤cookie的Secure标记
	//
	var cookie = resHeader['set-cookie'] || [];
	for(var i = cookie.length - 1; i >= 0; --i) {
		cookie[i] = cookie[i].replace('; Secure', '');
	}

	var content_type = resHeader['content-type'] || '';
	var mime = content_type.split(';')[0];

	if (mime!="text/html")
	{
		clientRes.writeHead(serverRes.statusCode, resHeader);
		serverRes.pipe(clientRes);
		return;
	}

	//
	// gzip数据解压
	//
	var svrEnc = resHeader['content-encoding'];
	var stream = serverRes;

	if (svrEnc) {
		if (/gzip/i.test(svrEnc)) {
			stream = serverRes.pipe( zlib.createGunzip() );
		}
		else if (/deflate/i.test(svrEnc)) {
			stream = serverRes.pipe( zlib.createInflate() );
		}
	}

	//
	// 接收数据块到缓冲区
	//
	var data = new Buffer(0);

	stream.on('data', function(chunk) {
		data = Buffer.concat([data, chunk]);
	});

	stream.on('end', function() {
		//
		// 网页注入！
		//
		var charset = content_type.split('charset=')[1];
		data=inject.injectHtml(data, charset);

		//
		// 返回注入后的网页（尽可能压缩）
		//
		var usrEnc = clientReq.headers['accept-encoding'];
		if (usrEnc) {
			if (/gzip/i.test(usrEnc)) {
				usrEnc = zlib.gzip;
			}
			else if (/deflate/i.test(usrEnc)) {
				usrEnc = zlib.deflate;
			}
		}

		if (usrEnc) {
			usrEnc(data, function(err, bin) {
				err? BadReq() : flush(bin);
			});
		}
		else {
			flush(data);
		}

		function flush(data) {
			resHeader['content-length'] = data.length;
			clientRes.writeHead(serverRes.statusCode, resHeader);
			clientRes.end(data);
		}
	});

	stream.on('error', function() {
		console.log('================================= zlib error ======');
		BadReq();
	});

	function BadReq() {
		clientRes.writeHeader(404);
		clientRes.end();
	}
}

/**
 * 发起代理请求
 */
function proxyRequest(clientReq, clientRes) {

	var reqHeader = clientReq.headers;
	var host = reqHeader['host'];
	var url = host + clientReq.url;
	var fromHttpsPage;

	var referer = reqHeader['referer'];
	if (referer) {
		//
		// 防止referer暴露来源页，替换其中的http为https
		//
		var refUrl = referer.split('//')[1];

		fromHttpsPage = https_url[refUrl];
		if (fromHttpsPage) {
			referer = referer.replace('http', 'https');
		}
	}

	//
	// 目标url在https列表中，
	//    则用https代理访问。
	// 如果资源的引用页在https列表中，
	//    则有可能是引用页中的相对路径（相对路径没法分析是https还是http的），
	//    也使用用https代理该资源（一般https页面的资源基本都是https的）。
	//
	var secure = https_url[url] || fromHttpsPage;

	var fullUrl = (secure? 'https://' : 'http://') + url;

	console.log('[WEB] %s\t%s %s',
		clientReq.connection.remoteAddress,
		clientReq.method,
		fullUrl
	);

	// 代理请求参数
	var request = secure? https.request : http.request;
	var options = {
		hostname: host,
		port: secure? 443 : clientReq.socket.localPort,
		path: clientReq.url,
		method: clientReq.method,
		headers: reqHeader
	};

	var proxy = request(options, function(serverRes) {
		proxyResponse(clientReq, clientRes, serverRes, secure);
	});

	proxy.on('error', function() {
		console.log('[WEB] Error', fullUrl);
		//console.log(reqHeader);
		clientRes.writeHeader(404);
		clientRes.end();
	});

	clientReq.pipe(proxy);
}

/**
 * 客户端HTTP请求
 */
function onClientRequest(clientReq, clientRes) {
	var host = clientReq.headers['host'];
	if (!host) {
		return;
	}

	var domain = host.match(/[^:]*/) + '';
	proxyDns.addWebDomain(domain);

	proxyRequest(clientReq, clientRes);

}

/**
 * 添加Web服务端口
 */
exports.addPort = function(port) {
	var svr = http.createServer(onClientRequest);

	svr.listen(port, function() {
		console.log("[WEB] listening %s:%d",
			svr.address().address,
			svr.address().port
		);
	});

	svr.on('error', function() {
		console.log('[WEB] CANNOT listen %d', port);
	});

}

exports.addHttpsUrl = function(url) {
	if (url.indexOf('/') == -1) {
		url += '/';
	}
	https_url[url] = true;
}
<commit_msg>bug fix<commit_after>'use strict';

var proxyDns = require('./proxy_dns.js'),
	http = require('http'),
	https = require('https'),
	zlib = require('zlib'),
	inject=require('./inject');

var https_url = {};

/**
 * 处理代理响应
 */
function proxyResponse(clientReq, clientRes, serverRes, secure) {
	//console.log(serverRes.statusCode, serverRes.headers);

	//
	// 检测是否重定向到https站点
	//
	if (serverRes.statusCode == 302) {
		var newUrl = serverRes.headers['location'];

		if (newUrl && newUrl.substr(0, 8) == 'https://') {
			var url = newUrl.substr(8);
			https_url[url] = true;

			var pos = newUrl.indexOf('/', 8);
			clientReq.url = newUrl.substr(pos);
			clientReq.headers['host'] = newUrl.substring(8, pos);

			proxyRequest(clientReq, clientRes);
			clientReq.emit('end');

			console.log('[WEB] `%s` goto `%s`',
				clientReq.headers['host'] + clientReq.url,
				newUrl
			);
			return;
		}
	}

	var resHeader = serverRes.headers;

	//
	// 过滤cookie的Secure标记
	//
	var cookie = resHeader['set-cookie'] || [];
	for(var i = cookie.length - 1; i >= 0; --i) {
		cookie[i] = cookie[i].replace('; Secure', '');
	}

	var content_type = resHeader['content-type'] || '';
	var mime = content_type.split(';')[0];

	if (mime!="text/html")
	{
		clientRes.writeHead(serverRes.statusCode, resHeader);
		serverRes.pipe(clientRes);
		return;
	}

	//
	// gzip数据解压
	//
	var svrEnc = resHeader['content-encoding'];
	var stream = serverRes;

	if (svrEnc) {
		if (/gzip/i.test(svrEnc)) {
			stream = serverRes.pipe( zlib.createGunzip() );
		}
		else if (/deflate/i.test(svrEnc)) {
			stream = serverRes.pipe( zlib.createInflate() );
		}
	}

	//
	// 接收数据块到缓冲区
	//
	var data = new Buffer(0);

	stream.on('data', function(chunk) {
		data = Buffer.concat([data, chunk]);
	});

	stream.on('end', function() {
		//
		// 网页注入！
		//
		var charset = content_type.split('charset=')[1];
		data=inject.injectHtml(data, charset);

		flush(data);

		function flush(data) {
			resHeader['content-length'] = data.length;
			delete resHeader['content-encoding'];
			clientRes.writeHead(serverRes.statusCode, resHeader);
			clientRes.end(data);
		}
	});

	stream.on('error', function() {
		console.log('================================= zlib error ======');
		BadReq();
	});

	function BadReq() {
		clientRes.writeHeader(404);
		clientRes.end();
	}
}

/**
 * 发起代理请求
 */
function proxyRequest(clientReq, clientRes) {

	var reqHeader = clientReq.headers;
	var host = reqHeader['host'];
	var url = host + clientReq.url;
	var fromHttpsPage;

	var referer = reqHeader['referer'];
	if (referer) {
		//
		// 防止referer暴露来源页，替换其中的http为https
		//
		var refUrl = referer.split('//')[1];

		fromHttpsPage = https_url[refUrl];
		if (fromHttpsPage) {
			referer = referer.replace('http', 'https');
		}
	}

	//
	// 目标url在https列表中，
	//    则用https代理访问。
	// 如果资源的引用页在https列表中，
	//    则有可能是引用页中的相对路径（相对路径没法分析是https还是http的），
	//    也使用用https代理该资源（一般https页面的资源基本都是https的）。
	//
	var secure = https_url[url] || fromHttpsPage;

	var fullUrl = (secure? 'https://' : 'http://') + url;

	console.log('[WEB] %s\t%s %s',
		clientReq.connection.remoteAddress,
		clientReq.method,
		fullUrl
	);

	// 代理请求参数
	var request = secure? https.request : http.request;
	var options = {
		hostname: host,
		port: secure? 443 : clientReq.socket.localPort,
		path: clientReq.url,
		method: clientReq.method,
		headers: reqHeader
	};

	var proxy = request(options, function(serverRes) {
		proxyResponse(clientReq, clientRes, serverRes, secure);
	});

	proxy.on('error', function() {
		console.log('[WEB] Error', fullUrl);
		//console.log(reqHeader);
		clientRes.writeHeader(404);
		clientRes.end();
	});

	clientReq.pipe(proxy);
}

/**
 * 客户端HTTP请求
 */
function onClientRequest(clientReq, clientRes) {
	var host = clientReq.headers['host'];
	if (!host) {
		return;
	}

	var domain = host.match(/[^:]*/) + '';
	proxyDns.addWebDomain(domain);

	proxyRequest(clientReq, clientRes);

}

/**
 * 添加Web服务端口
 */
exports.addPort = function(port) {
	var svr = http.createServer(onClientRequest);

	svr.listen(port, function() {
		console.log("[WEB] listening %s:%d",
			svr.address().address,
			svr.address().port
		);
	});

	svr.on('error', function() {
		console.log('[WEB] CANNOT listen %d', port);
	});

}

exports.addHttpsUrl = function(url) {
	if (url.indexOf('/') == -1) {
		url += '/';
	}
	https_url[url] = true;
}
<|endoftext|>


<commit_before>'use strict';

const _ = require('underscore');
const moment = require('moment');

module.exports = (repos) => {

  let reposInMd = ``;
  let years = [];
  let months = []

  _.each(repos, (repo) => {

    let year = moment(repo.created_at).year();
    let month = moment(repo.created_at).month();
    let monthText = moment(repo.created_at).format('MMM');

    if (!_.contains(years, year)) {
      reposInMd += `### ${year}\n`;
      years.push(year);
    }

    if (!_.contains(months, month)) {
      reposInMd += `##### ${monthText}\n`;
      months.push(month);
    }

    reposInMd += `- [\`${repo.name}\`](repo.url) ${repo.description}\n\n`;
  });

  return reposInMd;
};
<commit_msg>Fix repo URL<commit_after>'use strict';

const _ = require('underscore');
const moment = require('moment');

module.exports = (repos) => {

  let reposInMd = ``;
  let years = [];
  let months = []

  _.each(repos, (repo) => {

    let year = moment(repo.created_at).year();
    let month = moment(repo.created_at).month();
    let monthText = moment(repo.created_at).format('MMM');

    if (!_.contains(years, year)) {
      reposInMd += `### ${year}\n`;
      years.push(year);
    }

    if (!_.contains(months, month)) {
      reposInMd += `##### ${monthText}\n`;
      months.push(month);
    }

    reposInMd += `- [\`${repo.name}\`](${repo.html_url}) ${repo.description}\n\n`;
  });

  return reposInMd;
};
<|endoftext|>


<commit_before>
module.exports = function(pagerun){
    var self = this;
    var config = self.config({});
    var arrTop = [];
    var arrHeader = [];
    var arrBody = [];
    var arrFooter = [];
    if(config.top){
        arrTop.push(config.top);
    }
    if(config.header){
        arrHeader.push(config.header);
    }
    if(config.body){
        arrBody.push(config.body);
    }
    if(config.footer){
        arrFooter.push(config.footer);
    }
    var bOpenUrl = false;
    // insert js at the first
    pagerun.injectCodeBefore = function(code, pos){
        switch(pos){
            case 'top':
                arrTop.unshift(code);
                break;
            case 'header':
                arrHeader.unshift(code);
                break;
            case 'body':
                arrBody.unshift(code);
                break;
            case 'footer':
                arrFooter.unshift(code);
                break;
        }
    }
    // append js at the end
    pagerun.injectCode = function(code, pos){
        switch(pos){
            case 'top':
                arrTop.push(code);
                break;
            case 'header':
                arrHeader.push(code);
                break;
            case 'body':
                arrBody.push(code);
                break;
            case 'footer':
                arrFooter.push(code);
                break;
        }
    }
    pagerun.on('proxyStart', function(msg){
        var proxy = msg.proxy;
        proxy.addFilter(function(httpData, next){
            if(bOpenUrl === true){
                var responseContent = httpData.responseContent;
                if(httpData.responseCode === 200 &&
                    httpData.responseType === 'html' &&
                    responseContent !== undefined){
                    var codeTop = arrTop.join('\r\n');
                    var codeHeader = arrHeader.join('\r\n');
                    var codeBody = arrBody.join('\r\n');
                    var codeFooter = arrFooter.join('\r\n');
                    if(codeTop){
                        responseContent = responseContent.replace(/<head(\s+[^<>]*)?>/i, '$&\r\n'+codeTop);
                    }
                    if(codeHeader){
                        responseContent = responseContent.replace(/<\/head>/i, codeHeader+'\r\n$&');
                    }
                    if(codeBody){
                        responseContent = responseContent.replace(/<body(\s+[^<>]*)?>/i, '$&\r\n'+codeBody);
                    }
                    if(codeFooter){
                        responseContent = responseContent.replace(/<\/body>/i, codeFooter+'\r\n$&');
                    }
                    httpData.responseContent = responseContent;
                }
            }
            next();
        });
    });
    pagerun.on('webdriverOpenUrl', function(){
        bOpenUrl = true;
    });
};
<commit_msg>do not change the line no.<commit_after>
module.exports = function(pagerun){
    var self = this;
    var config = self.config({});
    var arrTop = [];
    var arrHeader = [];
    var arrBody = [];
    var arrFooter = [];
    if(config.top){
        arrTop.push(config.top);
    }
    if(config.header){
        arrHeader.push(config.header);
    }
    if(config.body){
        arrBody.push(config.body);
    }
    if(config.footer){
        arrFooter.push(config.footer);
    }
    var bOpenUrl = false;
    // insert js at the first
    pagerun.injectCodeBefore = function(code, pos){
        switch(pos){
            case 'top':
                arrTop.unshift(code);
                break;
            case 'header':
                arrHeader.unshift(code);
                break;
            case 'body':
                arrBody.unshift(code);
                break;
            case 'footer':
                arrFooter.unshift(code);
                break;
        }
    }
    // append js at the end
    pagerun.injectCode = function(code, pos){
        switch(pos){
            case 'top':
                arrTop.push(code);
                break;
            case 'header':
                arrHeader.push(code);
                break;
            case 'body':
                arrBody.push(code);
                break;
            case 'footer':
                arrFooter.push(code);
                break;
        }
    }
    pagerun.on('proxyStart', function(msg){
        var proxy = msg.proxy;
        proxy.addFilter(function(httpData, next){
            if(bOpenUrl === true){
                var responseContent = httpData.responseContent;
                if(httpData.responseCode === 200 &&
                    httpData.responseType === 'html' &&
                    responseContent !== undefined){
                    var codeTop = arrTop.join('');
                    var codeHeader = arrHeader.join('');
                    var codeBody = arrBody.join('');
                    var codeFooter = arrFooter.join('');
                    if(codeTop){
                        responseContent = responseContent.replace(/<head(\s+[^<>]*)?>/i, '$&'+codeTop);
                    }
                    if(codeHeader){
                        responseContent = responseContent.replace(/<\/head>/i, codeHeader+'$&');
                    }
                    if(codeBody){
                        responseContent = responseContent.replace(/<body(\s+[^<>]*)?>/i, '$&'+codeBody);
                    }
                    if(codeFooter){
                        responseContent = responseContent.replace(/<\/body>/i, codeFooter+'$&');
                    }
                    httpData.responseContent = responseContent;
                }
            }
            next();
        });
    });
    pagerun.on('webdriverOpenUrl', function(){
        bOpenUrl = true;
    });
};
<|endoftext|>


<commit_before>var parse5 = require('parse5'),
    request = require('request'),
    EnvironmentOperator = require('./operators/control_flow/environment');

//Monad-inspired control flow: rollback to the previous value if the new one is undefined.
function transanctional(currentValue, newValue) {
    if (newValue !== undefined)
        return newValue;

    return currentValue;
}

//ProcessorBase
var ProcessorBase = function () {
    this.operators = [EnvironmentOperator];

    this.environment = {
        baseUrl: null,
        inElement: null,
        inBody: false
    };

    var processor = this;

    //NOTE: we don't use .bind() here because it uses quite slow .apply() internally.
    this.parser = new parse5.SimpleApiParser({
        doctype: function (name, publicId, systemId) {
            processor._onDoctype(name, publicId, systemId);
        },

        startTag: function (tagName, attrs, selfClosing) {
            processor._onStartTag(tagName, attrs, selfClosing);
        },

        endTag: function (tagName) {
            processor._onEndTag(tagName);
        },

        text: function (text) {
            processor._onText(text);
        },

        comment: function (comment) {
            processor._onComment(comment);
        }
    });
};

//Pure virtual
ProcessorBase.prototype.aggregateOperatorResults = null;

//Parser handlers
ProcessorBase.prototype._onDoctype = function (name, publicId, systemId) {
    var doctype = {
        name: name,
        publicId: publicId,
        systemId: systemId
    };

    for (var i = 0; i < this.operators.length; i++) {
        if (this.operators[i].onDoctype)
            doctype = transanctional(doctype, this.operators[i].onDoctype(doctype));
    }
};

ProcessorBase.prototype._onStartTag = function (tagName, attrs, selfClosing) {
    var startTag = {
        tagName: tagName,
        attrs: attrs,
        selfClosing: selfClosing
    };

    for (var i = 0; i < this.operators.length; i++) {
        if (this.operators[i].onStartTag)
            startTag = transanctional(startTag, this.operators[i].onStartTag(startTag));
    }
};

ProcessorBase.prototype._onEndTag = function (tagName) {
    for (var i = 0; i < this.operators.length; i++) {
        if (this.operators[i].onEndTag)
            tagName = transanctional(tagName, this.operators[i].onEndTag(tagName));
    }
};

ProcessorBase.prototype._onText = function (text) {
    for (var i = 0; i < this.operators.length; i++) {
        if (this.operators[i].onText)
            text = transanctional(text, this.operators[i].onText(text));
    }
};

ProcessorBase.prototype._onComment = function (comment) {
    for (var i = 0; i < this.operators.length; i++) {
        if (this.operators[i].onComment)
            comment = transanctional(comment, this.operators[i].onComment(comment));
    }
};

//API
ProcessorBase.prototype.fromHtml = function (html, baseUrl) {
    this.environment.baseUrl = baseUrl;
    this.environment.inElement = null;
    this.environment.inBody = false;

    for (var i = 0; i < this.operators.length; i++)
        this.operators[i].reset(this.environment);

    this.parser.parse(html);

    return this.aggregateOperatorResults();
};

ProcessorBase.prototype.from = function (options, callback) {
    var processor = this;

    request(options, function (err, response, body) {
        var results = null;

        if (!err) {
            //TODO decode body
            results = processor.fromHtml(body, options.url || options.uri || options);
        }

        callback(err, response, results);
    });
};
<commit_msg>Refactor transanctional<commit_after>var parse5 = require('parse5'),
    request = require('request'),
    EnvironmentOperator = require('./operators/control_flow/environment');

//Monad-inspired control flow: rollback to the previous value if the new one is undefined.
function transanctional(oldValue, newValue) {
    return newValue === undefined ? oldValue : newValue;
}

//ProcessorBase
var ProcessorBase = function () {
    this.operators = [EnvironmentOperator];

    this.environment = {
        baseUrl: null,
        inElement: null,
        inBody: false
    };

    var processor = this;

    //NOTE: we don't use .bind() here because it uses quite slow .apply() internally.
    this.parser = new parse5.SimpleApiParser({
        doctype: function (name, publicId, systemId) {
            processor._onDoctype(name, publicId, systemId);
        },

        startTag: function (tagName, attrs, selfClosing) {
            processor._onStartTag(tagName, attrs, selfClosing);
        },

        endTag: function (tagName) {
            processor._onEndTag(tagName);
        },

        text: function (text) {
            processor._onText(text);
        },

        comment: function (comment) {
            processor._onComment(comment);
        }
    });
};

//Pure virtual
ProcessorBase.prototype.aggregateOperatorResults = null;

//Parser handlers
ProcessorBase.prototype._onDoctype = function (name, publicId, systemId) {
    var doctype = {
        name: name,
        publicId: publicId,
        systemId: systemId
    };

    for (var i = 0; i < this.operators.length; i++) {
        if (this.operators[i].onDoctype)
            doctype = transanctional(doctype, this.operators[i].onDoctype(doctype));
    }
};

ProcessorBase.prototype._onStartTag = function (tagName, attrs, selfClosing) {
    var startTag = {
        tagName: tagName,
        attrs: attrs,
        selfClosing: selfClosing
    };

    for (var i = 0; i < this.operators.length; i++) {
        if (this.operators[i].onStartTag)
            startTag = transanctional(startTag, this.operators[i].onStartTag(startTag));
    }
};

ProcessorBase.prototype._onEndTag = function (tagName) {
    for (var i = 0; i < this.operators.length; i++) {
        if (this.operators[i].onEndTag)
            tagName = transanctional(tagName, this.operators[i].onEndTag(tagName));
    }
};

ProcessorBase.prototype._onText = function (text) {
    for (var i = 0; i < this.operators.length; i++) {
        if (this.operators[i].onText)
            text = transanctional(text, this.operators[i].onText(text));
    }
};

ProcessorBase.prototype._onComment = function (comment) {
    for (var i = 0; i < this.operators.length; i++) {
        if (this.operators[i].onComment)
            comment = transanctional(comment, this.operators[i].onComment(comment));
    }
};

//API
ProcessorBase.prototype.fromHtml = function (html, baseUrl) {
    this.environment.baseUrl = baseUrl;
    this.environment.inElement = null;
    this.environment.inBody = false;

    for (var i = 0; i < this.operators.length; i++)
        this.operators[i].reset(this.environment);

    this.parser.parse(html);

    return this.aggregateOperatorResults();
};

ProcessorBase.prototype.from = function (options, callback) {
    var processor = this;

    request(options, function (err, response, body) {
        var results = null;

        if (!err) {
            //TODO decode body
            results = processor.fromHtml(body, options.url || options.uri || options);
        }

        callback(err, response, results);
    });
};
<|endoftext|>


<commit_before>/*
  Copyright Jesús Pérez <jesusprubio@gmail.com>

  This code may only be used under the GPLv3 license found at
  http://www.gnu.org/licenses/gpl-3.0.txt.
*/

'use strict';

const requestP = require('request-promise');

const utils = require('../utils');
const defaultUa = require('../cfg').ua;

const Promise = utils.Promise;
const dbg = utils.dbg(__filename);

function getPromise(rhost, credPair, action, opts) {
  return new Promise((resolve, reject) => {
    const result = { up: false, authed: false };
    const port = opts.rport || 80;
    const transport = opts.transport || 'http';
    let url = `${transport}://${rhost}:${port}`;

    if (opts.path) { url = `${url}/path`; }
    const cliOpts = {
      url,
      headers: { 'User-Agent': opts.ua || defaultUa },
      resolveWithFullResponse: true,
      // TODO: Add the timeout to the rest of protocols.
      timeout: opts.timeout || 5000,
    };

    // https://github.com/request/request#http-authentication
    const finalCreds = credPair || [];
    cliOpts.auth = { user: finalCreds[0] || '', pass: finalCreds[1] || '' };

    // TODO: vs. "basic"
    // if (opts.digest === true) { reqOpts.auth.sendImmediately = false; }

    dbg('HTTP request setup:', cliOpts);
    requestP(cliOpts)
    .then((res) => {
      dbg('HTTP response correctly received');
      if (!utils.isObject(res)) {
        reject(new Error('Not valid HTTP response'));

        return;
      }

      result.data = {
        statusCode: res.statusCode,
        headers: res.headers,
        trailers: res.trailers,
        // TODO: Add an option because is too huge
        // body: res.body,
      };

      if (res.statusCode === 200) {
        dbg('Connected');
        result.up = true;
        result.authed = true;
      }

      if (!action) {
        resolve(result);
        return;
      }
    })
    .catch((err) => {
      if (err.statusCode) {
        result.up = true;
        result.data = {
          statusCode: err.statusCode,
          headers: err.response.headers,
          trailers: err.response.trailers,
          // TODO: Add an option because is too huge
          // body: res.body,
        };
        resolve(result);
      // Expected result, we dont want an error here.
      } else if (utils.includes([
        'ECONNREFUSED', 'ETIMEDOUT',
        'EHOSTUNREACH', 'EHOSTDOWN',
      ], err.cause.code)) {
        resolve(result);
      } else {
        reject(err);
      }
    });
  });
}

module.exports.map = (rhost, opts = {}) => getPromise(rhost, null, null, opts);

module.exports.brute = (rhost, credPair, opts = {}) => getPromise(rhost, credPair, null, opts);
<commit_msg>Issue already added for this.<commit_after>/*
  Copyright Jesús Pérez <jesusprubio@gmail.com>

  This code may only be used under the GPLv3 license found at
  http://www.gnu.org/licenses/gpl-3.0.txt.
*/

'use strict';

const requestP = require('request-promise');

const utils = require('../utils');
const defaultUa = require('../cfg').ua;

const Promise = utils.Promise;
const dbg = utils.dbg(__filename);

function getPromise(rhost, credPair, action, opts) {
  return new Promise((resolve, reject) => {
    const result = { up: false, authed: false };
    const port = opts.rport || 80;
    const transport = opts.transport || 'http';
    let url = `${transport}://${rhost}:${port}`;

    if (opts.path) { url = `${url}/path`; }
    const cliOpts = {
      url,
      headers: { 'User-Agent': opts.ua || defaultUa },
      resolveWithFullResponse: true,
      timeout: opts.timeout || 5000,
    };

    // https://github.com/request/request#http-authentication
    const finalCreds = credPair || [];
    cliOpts.auth = { user: finalCreds[0] || '', pass: finalCreds[1] || '' };

    // TODO: vs. "basic"
    // if (opts.digest === true) { reqOpts.auth.sendImmediately = false; }

    dbg('HTTP request setup:', cliOpts);
    requestP(cliOpts)
    .then((res) => {
      dbg('HTTP response correctly received');
      if (!utils.isObject(res)) {
        reject(new Error('Not valid HTTP response'));

        return;
      }

      result.data = {
        statusCode: res.statusCode,
        headers: res.headers,
        trailers: res.trailers,
        // TODO: Add an option because is too huge
        // body: res.body,
      };

      if (res.statusCode === 200) {
        dbg('Connected');
        result.up = true;
        result.authed = true;
      }

      if (!action) {
        resolve(result);
        return;
      }
    })
    .catch((err) => {
      if (err.statusCode) {
        result.up = true;
        result.data = {
          statusCode: err.statusCode,
          headers: err.response.headers,
          trailers: err.response.trailers,
          // TODO: Add an option because is too huge
          // body: res.body,
        };
        resolve(result);
      // Expected result, we dont want an error here.
      } else if (utils.includes([
        'ECONNREFUSED', 'ETIMEDOUT',
        'EHOSTUNREACH', 'EHOSTDOWN',
      ], err.cause.code)) {
        resolve(result);
      } else {
        reject(err);
      }
    });
  });
}

module.exports.map = (rhost, opts = {}) => getPromise(rhost, null, null, opts);

module.exports.brute = (rhost, credPair, opts = {}) => getPromise(rhost, credPair, null, opts);
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

define(function(require, exports, module) {

// Dependencies
const React = require("react");
const { Reps } = require("reps/repository");
const { isCropped } = require("reps/string");
const { TR, TD, SPAN, TABLE, TBODY } = Reps.DOM;

/**
 * @template This component represents a tree view with
 * expandable/collapsible nodes.
 */
var TreeView = React.createFactory(React.createClass(
/** @lends TreeView */
{
  displayName: "TreeView",

  getInitialState: function() {
    return {
      data: {},
      uid: 0,
      searchFilter: null
    };
  },

  // Rendering

  render: function() {
    var rows = [];
    var mode = this.props.mode;
    var state = this.state;

    var renderMembers = (members) => {
      for (var i in members) {
        var member = members[i];
        rows.push(TreeRow({
          tree: this,
          key: member.key,
          data: member,
          mode: mode,
          provider: this.props.provider,
          searchFilter: state.searchFilter || this.props.searchFilter
        }));

        if (member.children && member.children.length && member.open) {
          renderMembers(member.children);
        }
      };
    }

    renderMembers(this.state.data, 0);

    /*Trace.sysout("TreeView.render; rows", {
      rows: rows,
      state: state
    });*/

    return (
      TABLE({className: "domTable", cellPadding: 0, cellSpacing: 0,
        onClick: this.onClick},
        TBODY({}, rows)
      )
    );
  },

  // Event Handlers

  onClick: function(event) {
    this.setState({data: this.state.data});
  },

  // Data

  componentDidMount: function() {
    Trace.sysout("TreeView.componentDidMount", this.props);

    var members = this.initMembers(this.props.data, 0);
    this.setState({data: members, searchFilter: this.props.searchFilter});
  },

  componentWillReceiveProps: function(nextProps) {
    var updatedState = {
      searchFilter: nextProps.searchFilter
    };

    var update = nextProps.forceUpdate || (this.props.data !== nextProps.data);

    Trace.sysout("TreeView.componentWillReceiveProps; update: " +
      update, nextProps);

    if (update) {
      updatedState.data = this.initMembers(nextProps.data, 0);
    }

    this.setState(updatedState);
  },

  initMembers: function(parent, level) {
    var members = this.getMembers(parent, level);
    if (!members) {
      return;
    }

    Trace.sysout("TreeView.initMembers; " + level, parent);

    for (var i in members) {
      var member = members[i];

      // Children for some nodes can be fetched when the node
      // is actually expanded (in the UI) for the first time.
      if (member.lazyLoad && !member.open) {
        continue;
      }

      // Cropped strings are expandable, but they don't have children.
      var isString = typeof(member.value) == "string";
      if (member.hasChildren && !isString) {
        member.children = this.initMembers(member.value, level+1);
      }
    };
    return members;
  },

  getMembers: function(object, level) {
    level = level || 0;

    if (this.props.provider) {
      return this.fetchMembers(object, level);
    }

    var getObjectProperties = this.props.getObjectProperties ||
      this.getObjectProperties.bind(this);
    var hasProperties = this.props.hasProperties ||
      this.hasProperties.bind(this);

    // Iterate over all properties and create 'members' - data
    // structures representing the tree state.
    var members = [];
    getObjectProperties(object, (prop, value) => {
      var hasChildren = hasProperties(value);

      // Cropped strings are expandable, so the user can see the
      // entire original value.
      if (isCropped(value)) {
        hasChildren = true;
      }

      var type = this.getType(value);
      var member = this.createMember(type, prop, value, level, hasChildren);
      members.push(member);
    });

    return members;
  },

  fetchMembers: function(object, level) {
    var provider = this.props.provider;
    var children = provider.getChildren(object);
    if (children instanceof Promise) {
      return;
    }

    Trace.sysout("TreeView.fetchMembers;", children);

    var members = [];
    for (var i=0; i<children.length; i++) {
      var child = children[i];
      var hasChildren = provider.hasChildren(child);
      var name = provider.getLabel(child);
      var type = this.getType(child);

      var member = this.createMember(type, name, child, level, hasChildren);
      member.lazyLoad = true;
      member.provider = provider;
      members.push(member);
    }

    return members;
  },

  createMember: function(type, name, value, level, hasChildren) {
    var member = {
      name: name,
      type: type,
      rowClass: "memberRow-" + type,
      open: "",
      level: level,
      hasChildren: hasChildren,
      value: value,
      open: false,
      key: this.state.uid++
    };

    return member;
  },

  getObjectProperties: function(obj, callback) {
    for (var p in obj) {
      try {
        callback.call(this, p, obj[p]);
      }
      catch (e) {
        console.log(e)
        Trace.sysout("domTree.getObjectProperties; EXCEPTION " + e, e);
      }
    }
  },

  hasProperties: function(obj) {
    var type = typeof(obj);
    if (type === "string") {
      return false;
    }

    if (type !== "object") {
      return false;
    }

    try {
      for (var name in obj) {
        return true;
      }
    }
    catch (exc) {
    }

    return false;
  },

  getType: function(object) {
    // xxxHonza: A type provider (or a decorator) should be used here.
    return "dom";
  }
}));

/**
 * @template Represents a node in TreeView template.
 */
var TreeRow = React.createFactory(React.createClass({
  displayName: "TreeRow",

  getInitialState: function() {
    return { data: {}, searchFilter: null };
  },

  componentDidMount: function() {
    this.setState({data: this.props.data});
  },

  render: function() {
    var member = this.state.data;
    var classNames = ["memberRow"];
    classNames.push(member.type + "Row");

    if (member.hasChildren) {
      classNames.push("hasChildren");
    }

    if (member.open) {
      classNames.push("opened");
    }

    if (member.loading) {
      classNames.push("spinning");
    }

    var filter = this.props.searchFilter;
    var name = member.name || "";
    var value = member.value || "";

    var provider = this.props.provider;
    if (provider) {
      value = provider.getValue(member.value);
    }

    if (filter && (name.indexOf(filter) < 0)) {
      // Cache the stringify result, so the filtering is fast
      // the next time.
      if (!member.valueString) {
        member.valueString = JSON.stringify(value);
      }

      if (member.valueString && member.valueString.indexOf(filter) < 0) {
        classNames.push("hidden");
      }
    }

    var rowStyle = {
      "paddingLeft": (member.level * 16) + "px",
    };

    /*Trace.sysout("TreeRow.render; " + member.name, {
      member: member,
      value: value,
    });*/

    var TAG = Reps.getRep(value);
    return (
      TR({className: classNames.join(" "), onClick: this.onClick},
        TD({className: "memberLabelCell", style: rowStyle},
          SPAN({className: "memberLabel " + member.type + "Label"},
            name)
        ),
        TD({className: "memberValueCell"},
          SPAN({},
            TAG({
              object: value,
              mode: this.props.mode,
              member: member,
              provider: provider
            })
          )
        )
      )
    )
  },

  onClick: function(event) {
    var member = this.state.data;
    var tree = this.props.tree;

    // Flip open flag.
    member.open = !member.open;

    // xxxHonza: refactor (do not use promises?)
    if (this.props.provider) {
      if (member.hasChildren && !member.children) {
        var properties = this.props.provider.getChildren(member.value);
        if (properties instanceof Promise) {
          member.loading = true;
          properties.then(props => {
            member.loading = false;

            member.children = tree.initMembers(member.value, member.level+1);
            this.setState({data: member});
          });
        } else {
          member.children = tree.initMembers(member.value, member.level+1);
          this.setState({data: member});
        }
      } else {
        this.setState({data: member});
      }
    }
  },
}));

// Exports from this module
exports.TreeView = TreeView;
});
<commit_msg>TreeView: support for xhtml<commit_after>/* See license.txt for terms of usage */

define(function(require, exports, module) {

// Dependencies
const React = require("react");
const { Reps } = require("reps/repository");
const { isCropped } = require("reps/string");
const { TR, TD, SPAN, TABLE, TBODY } = Reps.DOM;

/**
 * @template This component represents a tree view with
 * expandable/collapsible nodes.
 */
var TreeView = React.createFactory(React.createClass(
/** @lends TreeView */
{
  displayName: "TreeView",

  getInitialState: function() {
    return {
      data: {},
      uid: 0,
      searchFilter: null
    };
  },

  // Rendering

  render: function() {
    var rows = [];
    var mode = this.props.mode;
    var state = this.state;

    var renderMembers = (members) => {
      for (var i in members) {
        var member = members[i];
        rows.push(TreeRow({
          tree: this,
          key: member.key,
          data: member,
          mode: mode,
          provider: this.props.provider,
          searchFilter: state.searchFilter || this.props.searchFilter
        }));

        if (member.children && member.children.length && member.open) {
          renderMembers(member.children);
        }
      };
    }

    renderMembers(this.state.data, 0);

    /*Trace.sysout("TreeView.render; rows", {
      rows: rows,
      state: state
    });*/

    return (
      TABLE({className: "domTable", cellPadding: 0, cellSpacing: 0,
        onClick: this.onClick, ref: "domTable"},
        TBODY({}, rows)
      )
    );
  },

  // Event Handlers

  onClick: function(event) {
    this.setState({data: this.state.data});
  },

  // Data

  componentDidMount: function() {
    Trace.sysout("TreeView.componentDidMount", this.props);

    var members = this.initMembers(this.props.data, 0);
    this.setState({data: members, searchFilter: this.props.searchFilter});

    // ReactJS doesn't properly register event listeners if
    // the environment is XUL document. Let's do that manually
    // in such case.
    var target = this.refs.domTable.getDOMNode();
    var contentType = target.ownerDocument.contentType;
    if (contentType == "application/vnd.mozilla.xul+xml") {
      target.addEventListener("click", this.onClick, false);
    }
  },

  componentWillUnmount: function() {
    var target = this.refs.domTable.getDOMNode();
    var contentType = target.ownerDocument.contentType;
    if (contentType == "application/vnd.mozilla.xul+xml") {
      target.removeEventListener("click", this.onClick, false);
    }
  },

  componentWillReceiveProps: function(nextProps) {
    var updatedState = {
      searchFilter: nextProps.searchFilter
    };

    var update = nextProps.forceUpdate || (this.props.data !== nextProps.data);

    Trace.sysout("TreeView.componentWillReceiveProps; update: " +
      update, nextProps);

    if (update) {
      updatedState.data = this.initMembers(nextProps.data, 0);
    }

    this.setState(updatedState);
  },

  initMembers: function(parent, level) {
    var members = this.getMembers(parent, level);
    if (!members) {
      return;
    }

    //Trace.sysout("TreeView.initMembers; " + level, parent);

    for (var i in members) {
      var member = members[i];

      // Children for some nodes can be fetched when the node
      // is actually expanded (in the UI) for the first time.
      if (member.lazyLoad && !member.open) {
        continue;
      }

      // Cropped strings are expandable, but they don't have children.
      var isString = typeof(member.value) == "string";
      if (member.hasChildren && !isString) {
        member.children = this.initMembers(member.value, level+1);
      }
    };
    return members;
  },

  getMembers: function(object, level) {
    level = level || 0;

    if (this.props.provider) {
      return this.fetchMembers(object, level);
    }

    var getObjectProperties = this.props.getObjectProperties ||
      this.getObjectProperties.bind(this);
    var hasProperties = this.props.hasProperties ||
      this.hasProperties.bind(this);

    // Iterate over all properties and create 'members' - data
    // structures representing the tree state.
    var members = [];
    getObjectProperties(object, (prop, value) => {
      var hasChildren = hasProperties(value);

      // Cropped strings are expandable, so the user can see the
      // entire original value.
      if (isCropped(value)) {
        hasChildren = true;
      }

      var type = this.getType(value);
      var member = this.createMember(type, prop, value, level, hasChildren);
      members.push(member);
    });

    return members;
  },

  fetchMembers: function(object, level) {
    var provider = this.props.provider;
    var children = provider.getChildren(object);
    if (children instanceof Promise) {
      return;
    }

    Trace.sysout("TreeView.fetchMembers;", children);

    var members = [];
    for (var i=0; i<children.length; i++) {
      var child = children[i];
      var hasChildren = provider.hasChildren(child);
      var name = provider.getLabel(child);
      var type = this.getType(child);

      var member = this.createMember(type, name, child, level, hasChildren);
      member.lazyLoad = true;
      member.provider = provider;
      members.push(member);
    }

    return members;
  },

  createMember: function(type, name, value, level, hasChildren) {
    var member = {
      name: name,
      type: type,
      rowClass: "memberRow-" + type,
      open: "",
      level: level,
      hasChildren: hasChildren,
      value: value,
      open: false,
      key: this.state.uid++
    };

    return member;
  },

  getObjectProperties: function(obj, callback) {
    for (var p in obj) {
      try {
        callback.call(this, p, obj[p]);
      }
      catch (e) {
        console.log(e)
        Trace.sysout("domTree.getObjectProperties; EXCEPTION " + e, e);
      }
    }
  },

  hasProperties: function(obj) {
    var type = typeof(obj);
    if (type === "string") {
      return false;
    }

    if (type !== "object") {
      return false;
    }

    try {
      for (var name in obj) {
        return true;
      }
    }
    catch (exc) {
    }

    return false;
  },

  getType: function(object) {
    // xxxHonza: A type provider (or a decorator) should be used here.
    return "dom";
  }
}));

/**
 * @template Represents a node in TreeView template.
 */
var TreeRow = React.createFactory(React.createClass({
  displayName: "TreeRow",

  getInitialState: function() {
    return { data: {}, searchFilter: null };
  },

  componentDidMount: function() {
    this.setState({data: this.props.data});

    var target = this.refs.row.getDOMNode();
    var contentType = target.ownerDocument.contentType;
    if (contentType == "application/vnd.mozilla.xul+xml") {
      target.addEventListener("click", this.onClick, false);
    }
  },

  componentWillUnmount: function() {
    var target = this.refs.row.getDOMNode();
    var contentType = target.ownerDocument.contentType;
    if (contentType == "application/vnd.mozilla.xul+xml") {
      target.removeEventListener("click", this.onClick, false);
    }
  },

  render: function() {
    var member = this.state.data;
    var classNames = ["memberRow"];
    classNames.push(member.type + "Row");

    if (member.hasChildren) {
      classNames.push("hasChildren");
    }

    if (member.open) {
      classNames.push("opened");
    }

    if (member.loading) {
      classNames.push("spinning");
    }

    var filter = this.props.searchFilter;
    var name = member.name || "";
    var value = member.value || "";

    var provider = this.props.provider;
    if (provider) {
      value = provider.getValue(member.value);
    }

    if (filter && (name.indexOf(filter) < 0)) {
      // Cache the stringify result, so the filtering is fast
      // the next time.
      if (!member.valueString) {
        member.valueString = JSON.stringify(value);
      }

      if (member.valueString && member.valueString.indexOf(filter) < 0) {
        classNames.push("hidden");
      }
    }

    var rowStyle = {
      "paddingLeft": (member.level * 16) + "px",
    };

    /*Trace.sysout("TreeRow.render; " + member.name, {
      member: member,
      value: value,
    });*/

    var TAG = Reps.getRep(value);
    return (
      TR({className: classNames.join(" "), onClick: this.onClick, ref: "row"},
        TD({className: "memberLabelCell", style: rowStyle},
          SPAN({className: "memberLabel " + member.type + "Label"},
            name)
        ),
        TD({className: "memberValueCell"},
          SPAN({},
            TAG({
              object: value,
              mode: this.props.mode,
              member: member,
              provider: provider
            })
          )
        )
      )
    )
  },

  onClick: function(event) {
    var member = this.state.data;
    var tree = this.props.tree;

    // Flip open flag.
    member.open = !member.open;

    // xxxHonza: refactor (do not use promises?)
    if (this.props.provider) {
      if (member.hasChildren && !member.children) {
        var properties = this.props.provider.getChildren(member.value);
        if (properties instanceof Promise) {
          member.loading = true;
          properties.then(props => {
            member.loading = false;

            member.children = tree.initMembers(member.value, member.level+1);
            this.setState({data: member});
          });
        } else {
          member.children = tree.initMembers(member.value, member.level+1);
          this.setState({data: member});
        }
      } else {
        this.setState({data: member});
      }
    }
    else {
      member.children = tree.initMembers(member.value, member.level+1);
      this.setState({data: member});
    }
  },
}));

// Exports from this module
exports.TreeView = TreeView;
});
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

define(function(require, exports, module) {

// Dependencies
const React = require("react");
const { Reps } = require("reps/repository");
const { isCropped } = require("reps/string");
const { TR, TD, SPAN, TABLE, TBODY } = Reps.DOM;

/**
 * @template This component represents a tree view with
 * expandable/collapsible nodes.
 */
var TreeView = React.createFactory(React.createClass(
/** @lends TreeView */
{
  displayName: "TreeView",

  getInitialState: function() {
    return {
      data: {},
      uid: 0,
      searchFilter: null
    };
  },

  // Rendering

  render: function() {
    var rows = [];
    var mode = this.props.mode;
    var state = this.state;

    var rowRep = this.props.rowRep || TreeRow;

    var renderMembers = (members) => {
      for (var i in members) {
        var member = members[i];
        rows.push(TreeRow({
          tree: this,
          key: member.key,
          data: member,
          mode: mode,
          listener: this.props.listener,
          provider: this.props.provider,
          decorator: this.props.decorator,
          searchFilter: state.searchFilter || this.props.searchFilter
        }));

        if (member.children && member.children.length && member.open) {
          renderMembers(member.children);
        }
      };
    }

    renderMembers(this.state.members, 0);

    return (
      TABLE({className: "domTable", cellPadding: 0, cellSpacing: 0,
        onClick: this.onClick},
        TBODY({}, rows)
      )
    );
  },

  // Event Handlers

  onClick: function(event) {
    this.setState({members: this.state.members});
  },

  // Data

  componentDidMount: function() {
    if (this.state.members) {
      return;
    }

    var members = this.initMembers(this.props.data, 0);

    this.setState({
      members: members,
      searchFilter: this.props.searchFilter
    });
  },

  componentWillReceiveProps: function(nextProps) {
    var updatedState = {
      searchFilter: nextProps.searchFilter
    };

    var update = nextProps.forceUpdate || (this.props.data !== nextProps.data);

    if (update) {
      updatedState.members = this.initMembers(nextProps.data, 0);
    }

    this.setState(updatedState);
  },

  initMembers: function(parent, level) {
    var members = this.getMembers(parent, level);
    if (!members) {
      return;
    }

    for (var i in members) {
      var member = members[i];

      // Children for some nodes can be fetched when the node
      // is actually expanded (in the UI) for the first time.
      if (member.lazyLoad && !member.open) {
        continue;
      }

      // Cropped strings are expandable, but they don't have children.
      var isString = typeof(member.value) == "string";
      if (member.hasChildren && !isString) {
        member.children = this.initMembers(member.value, level+1);
      }
    };

    return members;
  },

  getMembers: function(object, level) {
    level = level || 0;

    if (this.props.provider) {
      return this.fetchMembers(object, level);
    }

    var getObjectProperties = this.props.getObjectProperties ||
      this.getObjectProperties;
    var hasProperties = this.props.hasProperties ||
      this.hasProperties;

    // Iterate over all properties and create 'members' - data
    // structures representing the tree state.
    var members = [];
    getObjectProperties(object, (prop, value) => {
      var hasChildren = hasProperties(value);

      // Cropped strings are expandable, so the user can see the
      // entire original value.
      if (isCropped(value)) {
        hasChildren = true;
      }

      var type = this.getType(value);
      var member = this.createMember(type, prop, value, level, hasChildren);
      members.push(member);
    });

    return members;
  },

  fetchMembers: function(object, level) {
    var provider = this.props.provider;
    var children = provider.getChildren(object);
    if (!children) {
      return;
    }

    if (children instanceof Promise) {
      return;
    }

    var members = [];
    for (var i=0; i<children.length; i++) {
      var child = children[i];
      var hasChildren = provider.hasChildren(child);
      var name = provider.getLabel(child);
      var value = provider.getValue(child);
      var type = this.getType(child);

      // Cropped strings are expandable, so the user can see the
      // entire original value.
      if (isCropped(value)) {
        hasChildren = true;
      }

      var member = this.createMember(type, name, child, level, hasChildren);
      member.lazyLoad = true;
      member.provider = provider;
      member.decorator = this.props.decorator;
      members.push(member);
    }

    return members;
  },

  createMember: function(type, name, value, level, hasChildren) {
    var member = {
      name: name,
      type: type,
      rowClass: "memberRow-" + type,
      open: "",
      level: level,
      hasChildren: hasChildren,
      value: value,
      open: false,
      lazyLoad: true,
      key: this.state.uid++
    };

    return member;
  },

  getObjectProperties: function(obj, callback) {
    for (var p in obj) {
      try {
        callback.call(this, p, obj[p]);
      }
      catch (e) {
        console.log("domTree.getObjectProperties; EXCEPTION " + e, e);
      }
    }
  },

  hasProperties: function(obj) {
    var type = typeof(obj);
    if (type === "string") {
      return false;
    }

    if (type !== "object") {
      return false;
    }

    try {
      for (var name in obj) {
        return true;
      }
    }
    catch (exc) {
    }

    return false;
  },

  getType: function(object) {
    return "dom";
  },
}));

/**
 * @template Represents a node in TreeView template.
 */
var TreeRow = React.createFactory(React.createClass({
  displayName: "TreeRow",

  getInitialState: function() {
    return { data: {}, searchFilter: null };
  },

  componentDidMount: function() {
    this.setState({data: this.props.data});
  },

  getRowClassNames: function(object) {
    var decorator = this.props.decorator;
    if (decorator && typeof decorator.getRowClassNames == "function") {
      return decorator.getRowClassNames(object);
    }
  },

  render: function() {
    var member = this.state.data;
    var classNames = this.getRowClassNames(member.value) || [];
    classNames.push("memberRow");
    classNames.push(member.type + "Row");

    if (member.hasChildren) {
      classNames.push("hasChildren");
    }

    if (member.open) {
      classNames.push("opened");
    }

    if (member.loading) {
      classNames.push("spinning");
    }

    var filter = this.props.searchFilter;
    var name = member.name || "";
    var value = member.value || "";

    var provider = this.props.provider;
    if (provider) {
      value = provider.getValue(member.value);
    }

    if (filter && (name.indexOf(filter) < 0)) {
      // Cache the stringify result, so the filtering is fast
      // the next time.
      if (!member.valueString) {
        member.valueString = JSON.stringify(value);
      }

      if (member.valueString && member.valueString.indexOf(filter) < 0) {
        classNames.push("hidden");
      }
    }

    var level = member.level || 0;
    var rowStyle = {
      "paddingLeft": (level * 16) + "px",
    };

    var TAG;

    var decorator = this.props.decorator;
    if (decorator && typeof getValueRep == "function") {
      TAG = decorator.getValueRep(value);
    }

    if (!TAG) {
      TAG = Reps.getRep(value);
    }

    return (
      TR({className: classNames.join(" "), onClick: this.onClick},
        TD({className: "memberLabelCell", style: rowStyle},
          SPAN({className: "memberLabel " + member.type + "Label"},
            name)
        ),
        TD({className: "memberValueCell"},
          SPAN({},
            TAG({
              object: value,
              mode: this.props.mode,
              member: member,
              provider: provider,
              decorator: decorator
            })
          )
        )
      )
    )
  },

  onClick: function(event) {
    if (event.target.classList.contains("memberLabel")) {
      var member = this.state.data;
      var tree = this.props.tree;

      if (!member.hasChildren) {
        return;
      }

      // Flip open flag.
      member.open = !member.open;

      // xxxHonza: refactor (do not use promises?)
      if (this.props.provider) {
        var value = this.props.provider.getValue(member.value);
        if (typeof(value) == "string") {
          // Cropped strings don't have children
          this.setState({data: member});
        } else if (member.hasChildren && !member.children) {
          var properties = this.props.provider.getChildren(member.value);
          if (properties instanceof Promise) {
            member.loading = true;
            properties.then(props => {
              member.loading = false;

              member.children = tree.initMembers(member.value, member.level+1);
              this.setState({data: member});
            });
          } else {
            member.children = tree.initMembers(member.value, member.level+1);
            this.setState({data: member});
          }
        } else {
          this.setState({data: member});
        }
      }
      else {
        if (!member.children) {
          member.children = tree.initMembers(member.value, member.level+1);
        }
        this.setState({data: member});
      }
    }

    dispatch(this.props.listener, "onRowClick", [this]);
  },
}));

// Helpers

function dispatch(listener, eventId, args) {
  if (listener && typeof listener[eventId] == "function") {
    listener[eventId].apply(listener, args);
  }
}

// Exports from this module
exports.TreeView = TreeView;
exports.TreeRow = TreeRow;
});
<commit_msg>TreeView: strings don't have children<commit_after>/* See license.txt for terms of usage */

define(function(require, exports, module) {

// Dependencies
const React = require("react");
const { Reps } = require("reps/repository");
const { isCropped } = require("reps/string");
const { TR, TD, SPAN, TABLE, TBODY } = Reps.DOM;

/**
 * @template This component represents a tree view with
 * expandable/collapsible nodes.
 */
var TreeView = React.createFactory(React.createClass(
/** @lends TreeView */
{
  displayName: "TreeView",

  getInitialState: function() {
    return {
      data: {},
      uid: 0,
      searchFilter: null
    };
  },

  // Rendering

  render: function() {
    var rows = [];
    var mode = this.props.mode;
    var state = this.state;

    var rowRep = this.props.rowRep || TreeRow;

    var renderMembers = (members) => {
      for (var i in members) {
        var member = members[i];
        rows.push(TreeRow({
          tree: this,
          key: member.key,
          data: member,
          mode: mode,
          listener: this.props.listener,
          provider: this.props.provider,
          decorator: this.props.decorator,
          searchFilter: state.searchFilter || this.props.searchFilter
        }));

        if (member.children && member.children.length && member.open) {
          renderMembers(member.children);
        }
      };
    }

    renderMembers(this.state.members, 0);

    return (
      TABLE({className: "domTable", cellPadding: 0, cellSpacing: 0,
        onClick: this.onClick},
        TBODY({}, rows)
      )
    );
  },

  // Event Handlers

  onClick: function(event) {
    this.setState({members: this.state.members});
  },

  // Data

  componentDidMount: function() {
    if (this.state.members) {
      return;
    }

    var members = this.initMembers(this.props.data, 0);

    this.setState({
      members: members,
      searchFilter: this.props.searchFilter
    });
  },

  componentWillReceiveProps: function(nextProps) {
    var updatedState = {
      searchFilter: nextProps.searchFilter
    };

    var update = nextProps.forceUpdate || (this.props.data !== nextProps.data);

    if (update) {
      updatedState.members = this.initMembers(nextProps.data, 0);
    }

    this.setState(updatedState);
  },

  initMembers: function(parent, level) {
    var members = this.getMembers(parent, level);
    if (!members) {
      return;
    }

    for (var i in members) {
      var member = members[i];

      // Children for some nodes can be fetched when the node
      // is actually expanded (in the UI) for the first time.
      if (member.lazyLoad && !member.open) {
        continue;
      }

      // Cropped strings are expandable, but they don't have children.
      var isString = typeof(member.value) == "string";
      if (member.hasChildren && !isString) {
        member.children = this.initMembers(member.value, level+1);
      }
    };

    return members;
  },

  getMembers: function(object, level) {
    level = level || 0;

    if (this.props.provider) {
      return this.fetchMembers(object, level);
    }

    // Strings don't have children. Note that 'long' strings are using
    // the expander icon (+/-) to display the entire original value,
    // but there are no child items.
    if (typeof(object) == "string") {
      return [];
    }

    var getObjectProperties = this.props.getObjectProperties ||
      this.getObjectProperties;
    var hasProperties = this.props.hasProperties ||
      this.hasProperties;

    // Iterate over all properties and create 'members' - data
    // structures representing the tree state.
    var members = [];
    getObjectProperties(object, (prop, value) => {
      var hasChildren = hasProperties(value);

      // Cropped strings are expandable, so the user can see the
      // entire original value.
      if (isCropped(value)) {
        hasChildren = true;
      }

      var type = this.getType(value);
      var member = this.createMember(type, prop, value, level, hasChildren);
      members.push(member);
    });

    return members;
  },

  fetchMembers: function(object, level) {
    var provider = this.props.provider;
    var children = provider.getChildren(object);
    if (!children) {
      return;
    }

    if (children instanceof Promise) {
      return;
    }

    var members = [];
    for (var i=0; i<children.length; i++) {
      var child = children[i];
      var hasChildren = provider.hasChildren(child);
      var name = provider.getLabel(child);
      var value = provider.getValue(child);
      var type = this.getType(child);

      // Cropped strings are expandable, so the user can see the
      // entire original value.
      if (isCropped(value)) {
        hasChildren = true;
      }

      var member = this.createMember(type, name, child, level, hasChildren);
      member.lazyLoad = true;
      member.provider = provider;
      member.decorator = this.props.decorator;
      members.push(member);
    }

    return members;
  },

  createMember: function(type, name, value, level, hasChildren) {
    var member = {
      name: name,
      type: type,
      rowClass: "memberRow-" + type,
      open: "",
      level: level,
      hasChildren: hasChildren,
      value: value,
      open: false,
      lazyLoad: true,
      key: this.state.uid++
    };

    return member;
  },

  getObjectProperties: function(obj, callback) {
    for (var p in obj) {
      try {
        callback.call(this, p, obj[p]);
      }
      catch (e) {
        console.log("domTree.getObjectProperties; EXCEPTION " + e, e);
      }
    }
  },

  hasProperties: function(obj) {
    var type = typeof(obj);
    if (type === "string") {
      return false;
    }

    if (type !== "object") {
      return false;
    }

    try {
      for (var name in obj) {
        return true;
      }
    }
    catch (exc) {
    }

    return false;
  },

  getType: function(object) {
    return "dom";
  },
}));

/**
 * @template Represents a node in TreeView template.
 */
var TreeRow = React.createFactory(React.createClass({
  displayName: "TreeRow",

  getInitialState: function() {
    return { data: {}, searchFilter: null };
  },

  componentDidMount: function() {
    this.setState({data: this.props.data});
  },

  getRowClassNames: function(object) {
    var decorator = this.props.decorator;
    if (decorator && typeof decorator.getRowClassNames == "function") {
      return decorator.getRowClassNames(object);
    }
  },

  render: function() {
    var member = this.state.data;
    var classNames = this.getRowClassNames(member.value) || [];
    classNames.push("memberRow");
    classNames.push(member.type + "Row");

    if (member.hasChildren) {
      classNames.push("hasChildren");
    }

    if (member.open) {
      classNames.push("opened");
    }

    if (member.loading) {
      classNames.push("spinning");
    }

    var filter = this.props.searchFilter;
    var name = member.name || "";
    var value = member.value || "";

    var provider = this.props.provider;
    if (provider) {
      value = provider.getValue(member.value);
    }

    if (filter && (name.indexOf(filter) < 0)) {
      // Cache the stringify result, so the filtering is fast
      // the next time.
      if (!member.valueString) {
        member.valueString = JSON.stringify(value);
      }

      if (member.valueString && member.valueString.indexOf(filter) < 0) {
        classNames.push("hidden");
      }
    }

    var level = member.level || 0;
    var rowStyle = {
      "paddingLeft": (level * 16) + "px",
    };

    var TAG;

    var decorator = this.props.decorator;
    if (decorator && typeof getValueRep == "function") {
      TAG = decorator.getValueRep(value);
    }

    if (!TAG) {
      TAG = Reps.getRep(value);
    }

    return (
      TR({className: classNames.join(" "), onClick: this.onClick},
        TD({className: "memberLabelCell", style: rowStyle},
          SPAN({className: "memberLabel " + member.type + "Label"},
            name)
        ),
        TD({className: "memberValueCell"},
          SPAN({},
            TAG({
              object: value,
              mode: this.props.mode,
              member: member,
              provider: provider,
              decorator: decorator
            })
          )
        )
      )
    )
  },

  onClick: function(event) {
    if (event.target.classList.contains("memberLabel")) {
      var member = this.state.data;
      var tree = this.props.tree;

      if (!member.hasChildren) {
        return;
      }

      // Flip open flag.
      member.open = !member.open;

      // xxxHonza: refactor (do not use promises?)
      if (this.props.provider) {
        var value = this.props.provider.getValue(member.value);
        if (typeof(value) == "string") {
          // Cropped strings don't have children
          this.setState({data: member});
        } else if (member.hasChildren && !member.children) {
          var properties = this.props.provider.getChildren(member.value);
          if (properties instanceof Promise) {
            member.loading = true;
            properties.then(props => {
              member.loading = false;

              member.children = tree.initMembers(member.value, member.level+1);
              this.setState({data: member});
            });
          } else {
            member.children = tree.initMembers(member.value, member.level+1);
            this.setState({data: member});
          }
        } else {
          this.setState({data: member});
        }
      }
      else {
        if (!member.children) {
          member.children = tree.initMembers(member.value, member.level+1);
        }
        this.setState({data: member});
      }
    }

    dispatch(this.props.listener, "onRowClick", [this]);
  },
}));

// Helpers

function dispatch(listener, eventId, args) {
  if (listener && typeof listener[eventId] == "function") {
    listener[eventId].apply(listener, args);
  }
}

// Exports from this module
exports.TreeView = TreeView;
exports.TreeRow = TreeRow;
});
<|endoftext|>


<commit_before>const request = require('./promise-request')
const Url = require('./url')

/**
 * 获取楼层状态的状态
 * @param {Number} floor 楼层的编号
 */
async function getFloorStatus(floor = 3) {
  let { response, body } = await request(Url.Floor(floor), {
    json: true
  })

  if (response.statusCode !== 200) {
    throw new Error(`Bad status code ${response.status} when get floor status`);
  }

  return body
}

/**
 * 获取自习区域的状态
 * @param {AreaInfo} area 自习区域信息
 */
async function getAreaStatus(area) {
  const now = new Date;

  let { response, body } = await request(Url.Area(area), {
    json: true
  })

  if (response.statusCode !== 200) {
    throw new Error(`Bad status code ${response.status} when get area status`)
  }

  return body
}

/**
 * 预约座位
 * @param {Seat} seat 座位
 * @param {UserInfo} userInfo 用户信息
 * @param {Jar} jar Cookie 罐
 * @return
 */
async function book(seat, userInfo, jar) {
  const url = 'http://58.194.172.92:85/api.php/spaces/${seat.id}/book';

  let { response, body } = await request(url, {
    method: 'POST',
    form: {
      'access_token': userInfo.accessToken,
      'userid': userInfo.id,
      segment,
      'type': 1
    },
    headers: { cookie: jar.toString() },
    json: true
  });

  if (response.statusCode !== 200) {
    throw new Error(`Bad status code ${response.status} when book the seat`);
  }

  return body
}

module.exports = {
  getFloorStatus,
  getAreaStatus,
  book
}<commit_msg>Add function 'getTimeToken'<commit_after>const request = require('./promise-request')
const Url = require('./url')

/**
 * 获取楼层状态的状态
 * @param {Number} floor 楼层的编号
 */
async function getFloorStatus(floor = 3) {
  let { response, body } = await request(Url.Floor(floor), {
    json: true
  })

  if (response.statusCode !== 200) {
    throw new Error(`Bad status code ${response.status} when get floor status`);
  }

  return body
}

/**
 * 获取自习区域的状态
 * @param {AreaInfo} area 自习区域信息
 */
async function getAreaStatus(area) {
  const now = new Date;

  let { response, body } = await request(Url.Area(area), {
    json: true
  })

  if (response.statusCode !== 200) {
    throw new Error(`Bad status code ${response.status} when get area status`)
  }

  return body
}

/**
 * Get a time token, which is used in booking request
 * @param {Seat} seat The seat object
 * @param {Boolean} tomorrow Indicates today or tomorrow
 */
async function getTimeToken(area, tomorrow = false) {
  let date = new Date()

  if (tomorrow) {
    date.setDate(date.getDate() + 1)
  }

  let { response, body } = await request(Url.TimeToken(area.id, date), {
    json: true
  })

  if (response.statusCode !== 200) {
    throw new Error(`Bad status code ${response.status} when get available intervals`);
  }

  console.log(require('util').inspect(body, false, 4, true))
  return body.data.list[0].id
}

/**
 * 预约座位
 * @param {Seat} seat 座位
 * @param {User} user 用户信息
 * @param {Number} timeToken
 * @return
 */
async function book(seat, user, timeToken) {
  let { response, body } = await request(Url.Booking(seat.id), {
    method: 'POST',
    form: {
      'access_token': user.jar.get('access_token'),
      'userid': user.jar.get('userid'),
      'segment': timeToken,
      'type': 1
    },
    headers: { cookie: user.jar.toString() },
    json: true
  })

  if (response.statusCode !== 200) {
    throw new Error(`Bad status code ${response.status} when book the seat`);
  }

  return body
}

module.exports = {
  getFloorStatus,
  getAreaStatus,
  getTimeToken,
  book
}<|endoftext|>