#include <iostream>
#include <iomanip>
#include <limits>
#include <algorithm>
#include <vector>
#include <deque>
#include <queue>
#include <list>
#include <stack>
#include <string>
#include <functional>
#include <numeric>
#include <map>
#include <set>
#include <cstdlib>
#include <bitset>
#include <unordered_map>
#include <random>
#define _USE_MATH_DEFINES
#include <cmath>
#include <complex>
#include <cfloat>

using namespace std;

#define INFLD numeric_limits<double>::infinity()
// #define INF (int)1e8
// #define INFLL (long long)1e15
#define Loop(i, n) for(int i = 0; i < (int)n; i++)
#define Loop1(i, n) for(int i = 1; i <= (int)n; i++)
#define Loopr(i, n) for(int i = (int)n - 1; i >= 0; i--)
#define Loopr1(i, n) for(int i = (int)n; i >= 1; i--)
#define bitmanip(m,val) static_cast<bitset<(int)m>>(val)
typedef long long int ll;
typedef vector<int> vi;
typedef vector<vector<int>> vvi;
typedef pair<int, int> P;
typedef vector<ll> vll;
typedef vector<vector<ll>> vvll;

/*******************************************************/

namespace geometry {
  struct coordinate {
    double x, y;
    bool operator<(const coordinate & another) const {
      return x != another.x ? x < another.x : y < another.y;
    }
  };
  struct line {
    double a, b, c;
    pair<double, double> domain; // if b == 0, domain means range 
  };
  enum linetype {
    LINE, HALFLINE, SEGMENT
  };
  // ax + by + c = 0
  line make_line(double a, double b, double c, pair<double, double> domain = { -INFLD, INFLD }) {
    return{ a,b,c,domain };
  }
  // line from p through q when type is HALFLINE
  line make_line_through(coordinate p, coordinate q, linetype type = LINE) {
    line ret = { NAN, NAN, NAN,{ NAN,NAN } };
    if (p.x == q.x && p.y == q.y) return ret;
    else {
      if (p.x == q.x) {
        ret = { 1, 0, -p.x, {-INFLD, INFLD} };
        switch (type) {
        case SEGMENT:
          if (p.y > q.y) ret.domain = { q.y, p.y };
          else ret.domain = { p.y, q.y };
          return ret;
        case HALFLINE:
          if (p.y > q.y) ret.domain = { -INFLD, p.y };
          else ret.domain = { p.y, INFLD };
          return ret;
        case LINE:
          return ret;
        }
      }
      else {
        ret = { (q.y - p.y), (p.x - q.x), q.x * p.y - p.x * q.y,{ -INFLD, INFLD } };
        switch (type) {
        case SEGMENT:
          if (p.x > q.x) ret.domain = { q.x, p.x };
          else ret.domain = { p.x, q.x };
          return ret;
        case HALFLINE:
          if (p.x > q.x) ret.domain = { -INFLD, p.x };
          else ret.domain = { p.x, INFLD };
          return ret;
        case LINE:
          return ret;
        }
      }
    }
  }
  class Two_Lines {
  private:
    line l;
    line m;
    coordinate crosspoint; // (NAN, NAN) when not existing
    bool in_range(coordinate p, line l) {
      if (l.b == 0) {
        if (l.domain.first <= p.y && p.y <= l.domain.second) return true;
        else return false;
      }
      else {
        if (l.domain.first <= p.x && p.x <= l.domain.second) return true;
        else return false;
      }
    }
  public:
    bool is_intersect; // include having common interval
    bool is_parallel; // include having common interval
    bool is_orthogonal;
    Two_Lines(line l, line m) {
      Two_Lines::l = l;
      Two_Lines::m = m;
      is_intersect = false;
      is_parallel = false;
      is_orthogonal = false;
      crosspoint = { NAN, NAN };
      double dn = l.a * m.b - m.a * l.b;
      if (dn == 0) {
        is_parallel = true;
        if (l.a * m.c - m.a * l.c);
        else if (l.b * m.c - m.b * l.c);
        else {
          if (l.domain.first <= m.domain.second && m.domain.first <= l.domain.second) is_intersect = true;
          else is_intersect = false;
        }
      }
      else {
        if (!(l.a * m.a + l.b * m.b)) is_orthogonal = true;
        crosspoint.x = (l.b * m.c - m.b * l.c) / dn;
        crosspoint.y = (m.a * l.c - l.a * m.c) / dn;
        if (in_range(crosspoint, l) && in_range(crosspoint, m)) {
          is_intersect = true;
        }
        else {
          crosspoint = { NAN, NAN };
        }
      }
    }
    double get_distance() {
      return 0;
    }
    coordinate get_crosspoint() {
      return crosspoint;
    }
  };
}

int main() {
  using namespace geometry;
  int q; cin >> q;
  Loop(i, q) {
    coordinate p, q;
    line l, m;
    cin >> p.x >> p.y >> q.x >> q.y;
    l = make_line_through(p, q);
    cin >> p.x >> p.y >> q.x >> q.y;
    m = make_line_through(p, q);
    Two_Lines tls(l, m);
    if (tls.is_parallel) cout << 2 << endl;
    else if (tls.is_orthogonal) cout << 1 << endl;
    else cout << 0 << endl;
  }
}

/*
// the intersections of n lines
vector<coordinate> crosses_of_lines(vector<line> lines) {
  int n = lines.size();
  set<coordinate> st;
  Loop(i, n) {
    Loop(j, i) {
      coordinate p = cross_of_2_lines(lines[i], lines[j]);
      if (p.valid) st.insert(p);
    }
  }
  vector<coordinate> ret;
  for (auto itr = st.begin(); itr != st.end(); itr++) {
    ret.push_back(*itr);
  }
  return ret;
}

*/


Measured memory_bytes: 3244