You are given a set of n points on the plane. A line containing the origin is called good, if projection of the given set to this line forms a symmetric multiset of points. Find the total number of good lines.

Multiset is a set where equal elements are allowed.

Multiset is called symmetric, if there is a point P on the plane such that the multiset is [centrally symmetric](https://en.wikipedia.org/wiki/Point_reflection) in respect of point P.

Input

The first line contains a single integer n (1 ≤ n ≤ 2000) — the number of points in the set.

Each of the next n lines contains two integers xi and yi ( - 106 ≤ xi, yi ≤ 106) — the coordinates of the points. It is guaranteed that no two points coincide.

Output

If there are infinitely many good lines, print -1.

Otherwise, print single integer — the number of good lines.

Examples

Input

3
1 2
2 1
3 3


Output

3


Input

2
4 3
1 2


Output

-1

Note

Picture to the first sample test:

<image>

In the second sample, any line containing the origin is good.
#include <bits/stdc++.h>
inline int pidorand() { return ((rand() & 32767) << 15) | (rand() & 32767); }
using namespace std;
inline int nxt() {
  int x;
  scanf("%d", &x);
  return x;
}
long long gcd(long long a, long long b) { return b == 0 ? a : gcd(b, a % b); }
struct Point {
  long long x, y;
  Point(long long _x, long long _y) : x(_x), y(_y) {}
  Point() {}
  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  Point operator*(long long k) const { return Point(x * k, y * k); }
  long long vprod(const Point& p) const {
    return 1ll * x * p.y - 1ll * y * p.x;
  }
  Point normed() const {
    long long g = gcd(abs(x), abs(y));
    if (y > 0 || (y == 0 && x > 0)) {
      return Point(x / g, y / g);
    } else {
      return Point(-x / g, -y / g);
    }
  }
  bool operator<(const Point& p) const {
    return x < p.x || x == p.x && y < p.y;
  }
  bool operator==(const Point& p) const { return x == p.x && y == p.y; }
};
ostream& operator<<(ostream& ostr, const Point& pt) {
  ostr << "(" << pt.x << ", " << pt.y << ")";
  return ostr;
}
int32_t main() {
  long long n = nxt();
  long long mlt = n;
  Point cen(0, 0);
  vector<Point> a(n);
  for (long long i = 0; i < n; ++i) {
    long long x = nxt(), y = nxt();
    a[i] = Point(x, y);
    cen = cen + a[i];
  }
  for (long long i = 0; i < (long long)a.size(); ++i) {
    if (a[i] * n == cen) {
      a.erase(a.begin() + i);
      --i;
    }
  }
  for (long long i = 0; i < (long long)a.size(); ++i) {
    long long j = i + 1;
    while (j < (long long)a.size() && !((a[i] + a[j]) * n == cen * 2)) {
      ++j;
    }
    if (j < (long long)a.size()) {
      a.erase(a.begin() + j);
      a.erase(a.begin() + i);
      --i;
    }
  }
  n = a.size();
  if (n == 0) {
    puts("-1");
    return 0;
  }
  vector<Point> dirs;
  for (long long i = 0; i < n; ++i) {
    for (long long j = 0; j < i; ++j) {
      dirs.push_back(((a[i] + a[j]) * mlt - cen * 2).normed());
    }
  }
  sort((dirs).begin(), (dirs).end());
  long long ans = 0;
  for (long long i = 0; i < (long long)dirs.size();) {
    long long j = i;
    while (j < (long long)dirs.size() && dirs[i] == dirs[j]) {
      ++j;
    }
    if (j >= i + n / 2) {
      Point dir = dirs[i];
      vector<long long> vals;
      for (long long k = 0; k < n; ++k) {
        vals.push_back(a[k].vprod(dir));
      }
      sort((vals).begin(), (vals).end());
      bool ok = true;
      long long zlp = vals[0] + vals[n - 1];
      for (long long k = 0; k < (n + 1) / 2; ++k) {
        if (vals[k] + vals[n - 1 - k] != zlp) {
          ok = false;
          break;
        }
      }
      if (ok) {
        ++ans;
      }
    }
    i = j;
  }
  cout << ans << "\n";
  return 0;
}
