#include <bits/stdc++.h>
#define int long long
using namespace std;

struct R {
  double x, y;
  R(double _x, double _y) {
    x = _x;
    y = _y;
  }
  R() {}
};

struct Line {
  double A, B, C;
  Line (R a, R b) {
    A = b.y - a.y;
    B = a.x - b.x;
    C = a.y * b.x-a.x * b.y;
  }
  Line (double _A, double _B, double _C) {
    A = _A;
    B = _B;
    C = _C;
  }
  double slope() {
    assert(B != 0);
    return -A/B;
  }
};


signed main() {
  ios::sync_with_stdio(0);cin.tie(0);
  int n;
  cin >> n;
  vector<R> p(n);
  int answer = 0;
  for (int i = 0; i < n; ++i) cin >> p[i].x >> p[i].y;
  for (int i = 0; i < n; ++i) {
    for (int j = i + 1; j < n; ++j) {
      Line cur(p[i], p[j]);
      if (abs(cur.slope()) <= 1) ++answer;
    }
  }
  cout << answer;
}
#include<bits/stdc++.h>

#define IMAX 1<<29
#define PI 3.14159265359

using namespace std;

template <class T>
using Graph = vector<vector<T>>;

/******** Utility ***************/

int bsize(int bits, int _max){
  int c = 0;
  for(int ix=0; ix!=_max; ++ix)
    if((bits&(1<<ix)) !=0){
      ++c;
    }
  return c;
}

long factrial(long n){
  assert(n >= 0);
  if(n <= 1)
    return 1;
  long _sum = 1;
  for(int ix=0; ix!=(n-1); ++ix)
    _sum *= n-ix;
  return _sum;
}

template<typename T>
void show(vector<T> v)
{
  for(auto _v: v)
    cout << _v << " ";
  cout << endl;
}

template<typename T>
void show(vector<T> v, int maxrow)    // 適度に改行入れるver
{
  for(int ix=0; ix!=v.size(); ++ix){
    if(ix!=0 && ix%maxrow==0)
      cout << endl;
    cout << v[ix] << " ";
  }
  cout << endl;
}

template<typename T>
void show2(vector<vector<T>> v)
{
  int ix = 0;
  for(auto __v: v){
    cout << "[" << ix++ << "] (";
    for(auto _v: __v){
      cout << _v << ", ";
    }
    cout << ")" << endl;
  }
}

// G: Graph
// v: 次に訪れる頂点
// d: 最初に頂点を見つけたタイムスタンプ(行きがけ順)
//    -1で初期化されている必要がある
// f: ある頂点の隣接リストを探索し終えた時刻のタイムスタンプ(帰りがけ順)
//    -1で初期化されている必要がある
// timestamp: タイムスタンプ
// @return: vの隣接頂点の探索に要した時間
template<typename T>
void dfs(const Graph<T> &G, int v, vector<T> &d, vector<T> &f, T &timestamp)
{
  d[v] = timestamp++;
  for(auto next_v: G[v]){   // 隣接する頂点を探索
    if(d[next_v] != -1){  // 既に探索済み
      continue;
    }else{
      dfs(G, next_v, d, f, timestamp); // 次の頂点をDFS
    }
  }
  f[v] = timestamp++;
}

// G: Graph
// dist: startからの最小距離
// start: start地点
template<typename T>
void bfs(const Graph<T> &G, vector<int> &dist, const int start)
{
  // init
  queue<int> que;
  dist.assign(dist.size(), -1);
  dist[start] = 0;
  que.push(start);

  // BFS
  while(!que.empty()){
    int v = que.front();
    que.pop();
    for(auto next_v: G[v]){
      if(dist[next_v] != -1)  // 訪問済み
        continue;
      dist[next_v] = dist[v] + 1;
      que.push(next_v);
    }
  }
}

// グラフの周りに余白をつけていること前提
void genGraph(Graph<int> &G, vector<string> &board, int R, int C)
{
  for(int row=1; row!=R-1; ++row){
    for(int col=1; col!=C-1; ++col){
      if(board[row][col] == '#')
        continue;
      if(board[row-1][col] == '.')
        G[(row-1)*C + col].push_back(row*C + col);
      if(board[row][col-1] == '.')
        G[(row)*C + col-1].push_back(row*C + col);
      if(board[row][col+1] == '.')
        G[(row)*C + col+1].push_back(row*C + col);
      if(board[row+1][col] == '.')
        G[(row+1)*C + col].push_back(row*C + col);
    }
  }
}

/******** end of Utility ***************/

int main(void)
{
  // input
  int N;
  cin >> N;
  vector<double> x = vector<double>(N);
  vector<double> y = vector<double>(N);
  for(int ix=0; ix!=N; ++ix){
    cin >> x[ix] >> y[ix];
  }
  // main
  long count = 0;
  for(int ix=0; ix<N-1; ++ix){
    for(int jx=ix+1; jx<N; ++jx){
      if(abs((y[jx]-y[ix])/(x[jx]-x[ix])) <= 1){
        ++count;
      }
    }
  }

  // print
  cout << count << endl;
}