#include <iostream>
#include <algorithm>
#include <utility>
#include <vector>
#include <numeric>
#include <cmath>
#include <iomanip>

template <class T, class U>
inline bool chmin(T &lhs, const U &rhs) {
  if (lhs > rhs) {
    lhs = rhs;
    return true;
  }
  return false;
}

template <class T, class U>
inline bool chmax(T &lhs, const U &rhs) {
  if (lhs < rhs) {
    lhs = rhs;
    return true;
  }
  return false;
}

// [l, r) from l to r
struct range {
  struct itr {
    int i;
    constexpr itr(int i_): i(i_) { }
    constexpr void operator ++ () { ++i; }
    constexpr int operator * () const { return i; }
    constexpr bool operator != (itr x) const { return i != x.i; }
  };
  const itr l, r;
  constexpr range(int l_, int r_): l(l_), r(std::max(l_, r_)) { }
  constexpr itr begin() const { return l; }
  constexpr itr end() const { return r; }
};

// [l, r) from r to l
struct revrange {
  struct itr {
    int i;
    constexpr itr(int i_): i(i_) { }
    constexpr void operator ++ () { --i; }
    constexpr int operator * () const { return i; }
    constexpr bool operator != (itr x) const { return i != x.i; }
  };
  const itr l, r;
  constexpr revrange(int l_, int r_): l(l_ - 1), r(std::max(l_, r_) - 1) { }
  constexpr itr begin() const { return r; }
  constexpr itr end() const { return l; }
};


template <class T>
struct real_constant;

template <>
struct real_constant<double> {
  using value_type = double;
  static constexpr value_type infinity() { return 1e9; }
  static constexpr value_type epsilon() { return 1e-9; }
  static constexpr value_type pi() { return std::acos(-1.0); }
};

template <>
struct real_constant<long double> {
  using value_type = long double;
  static constexpr value_type infinity() { return 1e18; }
  static constexpr value_type epsilon() { return 1e-10; }
  static constexpr value_type pi() { return std::acos(-1.0L); }
};

template <>
struct real_constant<int> {
  using value_type = int;
  static constexpr value_type infinity() { return 1e9; }
  static constexpr value_type epsilon() { return 1; }
};

template <>
struct real_constant<long long> {
  using value_type = long long;
  static constexpr value_type infinity() { return 1e18; }
  static constexpr value_type epsilon() { return 1; }
};

template <class T, class U>
constexpr bool leq(T x, U y) {
  return x - y < real_constant<T>::epsilon();
}
template <class T, class U>
constexpr bool geq(T x, U y) {
  return y - x < real_constant<T>::epsilon();
}
template <class T, class U>
constexpr bool equal(T x, U y) {
  return leq(x, y) && geq(x, y);
}


template <class T>
struct vector_type {
  using value_type = T;
  value_type x, y;
  constexpr vector_type(): x(0), y(0) { }
  constexpr vector_type(value_type x_, value_type y_): x(x_), y(y_) { }
  constexpr vector_type &operator += (const vector_type &rhs) { x += rhs.x; y += rhs.y; return *this; }
  constexpr vector_type operator + (const vector_type &rhs) const { return vector_type(*this) += rhs; }
  constexpr vector_type &operator -= (const vector_type &rhs) { x -= rhs.x; y -= rhs.y; return *this; }
  constexpr vector_type operator - (const vector_type &rhs) const { return vector_type(*this) -= rhs; }
  constexpr vector_type operator - () const { return vector_type(-x, -y); }
  constexpr vector_type &operator *= (value_type rhs) { x *= rhs; y *= rhs; return *this; }
  constexpr vector_type &operator /= (value_type rhs) { x /= rhs; y /= rhs; return *this; }
  constexpr bool operator == (const vector_type &rhs) const { return equal(x, rhs.x) && equal(y, rhs.y); }
  constexpr bool operator != (const vector_type &rhs) const { return !equal(x, rhs.x) || !equal(y, rhs.y); }
};

template <class T, class U>
constexpr vector_type<T> operator * (vector_type<T> v, U rhs) { return v *= rhs; }
template <class T, class U>
constexpr vector_type<T> operator * (U rhs, vector_type<T> v) { return v *= rhs; }
template <class T, class U>
constexpr vector_type<T> operator / (vector_type<T> v, U rhs) { return v /= rhs; }

template <class T>
std::istream& operator >> (std::istream& is, vector_type<T> &v) { return is >> v.x >> v.y; }
template <class T>
std::ostream& operator << (std::ostream& os, const vector_type<T> &v) { return os << v.x << ' ' <<  v.y; }

template <class T>
constexpr T norm(const vector_type<T> &v) { return v.x * v.x + v.y * v.y; }
template <class T>
constexpr T abs(const vector_type<T> &v) { return std::sqrt(norm(v)); }
template <class T>
constexpr T argr(const vector_type<T> &v) { return std::atan2(v.y, v.x); }
template <class T>
constexpr T argd(const vector_type<T> &v) { return argr(v) * 180 / real_constant<T>::pi(); }
template <class T>
constexpr T dist(const vector_type<T> &v, const vector_type<T> &u) { return abs(v - u); }
template <class T>
constexpr T dot(const vector_type<T> &v, const vector_type<T> &u) { return v.x * u.x + v.y * u.y; }
template <class T>
constexpr T cross(const vector_type<T> &v, const vector_type<T> &u) { return v.x * u.y - v.y * u.x; }

template <class T>
constexpr unsigned orthan(const vector_type<T> &v) {
  if (v.x > 0 && v.y >= 0) return 0;
  if (v.x <= 0 && v.y > 0) return 1;
  if (v.x < 0 && v.y <= 0) return 2;
  if (v.x >= 0 && v.y < 0) return 3;
  return 0;
}
template <class T>
constexpr bool cmp_x(const vector_type<T> &v, const vector_type<T> &u) {
  if (equal(v.x, u.x)) return v.y < u.y;
  return v.x < u.x;
}
template <class T>
constexpr bool cmp_y(const vector_type<T> &v, const vector_type<T> &u) {
  if (equal(v.y, u.y)) return v.x < u.x;
  return v.y < u.y;
}
template <class T>
constexpr bool cmp_arg(const vector_type<T> &v, const vector_type<T> &u) {
  if (orthan(v) != orthan(u)) return orthan(v) < orthan(u);
  if (!equal(cross(v, u), 0)) return cross(v, u) > 0;
  return norm(v) < norm(u);
}

template <class T>
struct line_type {
  using value_type = T;
  value_type a, b, c;
  constexpr line_type(): a(0), b(0), c(0) { }
  constexpr line_type(value_type a_, value_type c_): a(a_), b(-1), c(c_) { }
  constexpr line_type(value_type a_, value_type b_, value_type c_): a(a_), b(b_), c(c_) { }
  constexpr value_type valx(value_type y) const { return (b * y + c) / (-a); }
  constexpr value_type valy(value_type x) const { return (a * x + c) / (-b); }
  constexpr bool operator == (const value_type &l) const { return equal(a * l.b, b * l.a) && equal(a * l.c, c * l.a); }
  constexpr bool operator != (const value_type &l) const { return !equal(a * l.b, b * l.a) || !equal(a * l.c, c * l.a); }
};

template <class T>
constexpr bool parallel(const line_type<T> &l, const line_type<T> &m) { return equal(l.a * m.b, l.b * m.a); };
template <class T>
constexpr bool vertical(const line_type<T> &l, const line_type<T> &m) { return equal(l.a * m.a + l.b * m.b, 0); };
template <class T>
constexpr bool is_on(const line_type<T> &l, const vector_type<T> &v) { return equal(l.a * v.x + l.b * v.y + l.c, 0);}
template <class T>
constexpr vector_type<T> intersection(const line_type<T> &l, const line_type<T> &m) {
  auto x = (l.b * m.c - l.c * m.b) / (l.a * m.b - l.b * m.a);
  auto y = (l.c * m.a - l.a * m.c) / (l.a * m.b - l.b * m.a);
  return vector_type<T>(x, y);
}
template <class T>
constexpr vector_type<T> direction(const line_type<T> &l) { vector_type<T> res(-l.b, l.a); return res; }
template <class T>
constexpr vector_type<T> perpend(const line_type<T> &l, const vector_type<T> &v) {
  auto u = vector_type<T>(l.a, l.b);
  auto d = -l.c / norm(u);
  auto e = dot(v, u) / norm(u);
  return (d - e) * u;
}
template <class T>
constexpr vector_type<T> project(const line_type<T> &l, const vector_type<T> &v) {
  return v + perpend(l, v);
}
template <class T>
constexpr vector_type<T> relfect(const line_type<T> &l, const vector_type<T> &v) {
  return v + perpend(l, v) * 2;
}
template <class T>
constexpr T dist(const line_type<T> &l, const vector_type<T> &v) { 
  return std::abs(l.a * v.x + l.b * v.y + l.c) / abs(vector_type<T>(l.a, l.b)); 
}

template <class T>
struct segment_type {
  using value_type = T;
  vector_type<value_type> st, en;
  constexpr segment_type(): st(0, 0), en(0, 0) { }
  constexpr segment_type(const vector_type<value_type> &l, const vector_type<value_type> &r): st(l), en(r) { }
  constexpr segment_type(value_type x1, value_type y1, value_type x2, value_type y2): st(x1, y1), en(x2, y2) { } 
  constexpr bool operator == (const segment_type &s) const { 
    return (st == s.st && en == s.en) || (st == s.en && en == s.st);
  }
  constexpr bool operator != (const segment_type &s) const { 
    return !(st == s.st && en == s.en) && !(st == s.en && en == s.st);
  }
};

template <class T>
constexpr vector_type<T> direction(const segment_type<T> &l) { return l.en - l.st; }
template <class T>
constexpr line_type<T> to_line(const segment_type<T> &s) {
  auto v = direction(s);
  auto c = v.y * s.st.x - v.x * s.st.y;
  return line_type<T>(-v.y, v.x, c);
}
template <class T>
constexpr line_type<T> bisect(const segment_type<T> &s) {
  auto v = direction(s), u = (s.st + s.en) / 2;
  return line_type<T>(v.x, v.y, -v.x * u.x - v.y * u.y);
}
template <class T>
constexpr bool intersects(const segment_type<T> &s, const segment_type<T> &t) {
  auto v = direction(s), u = direction(t);
  auto d = cross(v, t.st - s.st) * cross(v, t.en - s.st);
  auto e = cross(u, s.st - t.st) * cross(u, s.en - t.st);
  return leq(d, 0) && leq(e, 0);
}

int main() {
  int Q;
  std::cin >> Q;
  while (Q--) {
    segment_type<double> s1, s2;
    std::cin >> s1.st >> s1.en >> s2.st >> s2.en;
    auto l1 = to_line(s1), l2 = to_line(s2);
    if (parallel(l1, l2)) {
      std::cout << "2\n";
    }
    else if (vertical(l1, l2)) {
      std::cout << "1\n";
    }
    else {
      std::cout << "0\n";
    }
  }
  return 0;
}



Measured memory_bytes: 3232