#include <bits/stdc++.h>
using namespace std;
#define Rep(i,n) for(int i=0;i<(int)(n);i++)
#define For(i,n1,n2) for(int i=(int)(n1);i<(int)(n2);i++)
#define REP(i,n) for(ll i=0;i<(ll)(n);i++)
#define RREP(i,n) for(ll i=((ll)(n)-1);i>=0;i--)
#define FOR(i,n1,n2) for(ll i=(ll)(n1);i<(ll)(n2);i++)
#define RFOR(i,n1,n2) for(ll i=((ll)(n1)-1);i>=(ll)(n2);i--)
#define all(a)  (a).begin(),(a).end()
#define SORT(a) sort((a).begin(),(a).end())
#define oorret 0
#define oor(x) [&](){try{x;} catch(const out_of_range& oor){return oorret;} return x;}()
#define IOS cin.tie(0),ios::sync_with_stdio(false)
typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<ll, ll> P;
template<typename T1, typename T2> inline bool chmin(T1& a, T2 b) { if (a > b) { a = b; return 1; }return 0; }
template<typename T1, typename T2> inline bool chmax(T1& a, T2 b) { if (a < b) { a = b; return 1; }return 0; }
template<class Type>struct is_vector : std::false_type {};
template<class ValueType, class Alloc>struct is_vector<std::vector<ValueType, Alloc>> : std::true_type {};
template <typename T> inline std::ostream& operator << (std::ostream& out, const std::vector<T>& v) {
	if (v.empty())return out;
	constexpr bool is_vector_v = is_vector<T>::value;
	if (is_vector_v)for (auto itr = v.begin(); itr != v.end();)out << (*itr), out << ((++itr != v.end()) ? "\n" : "");
	else for (auto itr = v.begin(); itr != v.end();)out << (*itr), out << ((++itr != v.end()) ? " " : "");
	return out;
}
inline void put() {}
template<class T> inline void put(const T& first) { std::cout << first << "\n"; }
template<class T, class... N> inline void put(const T& first, const N& ... rest) { std::cout << first << " "; put(rest...); }
inline void putn() {}
template<class T, class... N> inline void putn(const T& first, const N& ... rest) { std::cout << first << "\n"; putn(rest...); }

template<typename T>class point {
public:
	T x, y;
	point(T x, T y) :x(x), y(y) {}
	point() :x(0), y(0) {}
	void set(T x, T y) {
		this->x = x;
		this->y = y;
	}
	T p2dist(point p) {
		T dx = x - p.x;
		T dy = y - p.y;
		return dx * dx + dy * dy;
	}
	T dist(point p) {
		return sqrt(p2dist(p));
	}
	T dist(T x, T y) {
		return dist(point(x, y));
	}
	T inner_product(point p) { // this・p
		return x * p.x + y * p.y;
	}
	T outer_product(point p) { // this × p
		return x * p.y - y * p.x;
	}
	T cos(point p1, point p2) { // 角度p1,this,p2の余弦
		point t1 = p1 - (*this), t2 = p2 - (*this);
		T ip = t1.inner_product(t2);
		return ip / t1.size() / t2.size();
	}
	T sin(point p1, point p2) { // 角度p1,this,p2の正弦
		point t1 = p1 - (*this), t2 = p2 - (*this);
		T ip = t1.outer_product(t2);
		return ip / t1.size() / t2.size();
	}
	T size() {
		return sqrt(x * x + y * y);
	}
	point norm() {
		return (*this) / size();
	}
	point project(point p1, point p2) { // p1,p2を通る直線へ下ろした垂線の足
		point p3 = p2 - p1;
		T s = p1.p2dist(p2);
		T t = (*this - p1) * p3 / s;
		point res = p3 * t;
		res += p1;
		return res;
	}
	point reflect(point p1, point p2) { // p1,p2を通る直線を軸とした線対称点
		point proj = this->project(p1, p2);
		point p = proj - (*this);
		p *= 2;
		point res = (*this) + p;
		return res;
	}
	T line_dist(point p1, point p2) { // p1,p2を通る直線との距離
		point proj = this->project(p1, p2);
		return this->dist(proj);
	}
	static bool isParallel(point p1, point p2, point p3, point p4) { // p1,p2を通る直線sとp3,p4を通る直線tが平行か
		point s = p2 - p1, t = p4 - p3;
		T op = s.outer_product(t);
		long double eps = 1e-10;
		if (s.size() < eps || t.size() < eps) {
			return false;
		}
		long double si = (long double)op / s.size() / t.size();
		return abs(si) < eps;
	}
	static bool isOrthogonal(point p1, point p2, point p3, point p4) { // p1,p2を通る直線sとp3,p4を通る直線tが垂直か
		point s = p2 - p1, t = p4 - p3;
		T ip = s * t;
		long double eps = 1e-10;
		if (s.size() < eps || t.size() < eps) {
			return false;
		}
		long double co = (long double)ip / s.size() / t.size();
		return abs(co) < eps;
	}
	point operator+(point p) { return point(x + p.x, y + p.y); }
	point operator-(point p) { return point(x - p.x, y - p.y); }
	point operator*(T t) { return point(x * t, y * t); }
	T operator*(point p) { return inner_product(p); }
	point operator/(T t) { return point(x / t, y / t); }
	void operator+=(point p) { x += p.x; y += p.y; }
	void operator-=(point p) { x -= p.x; y -= p.y; }
	void operator*=(T t) { x *= t; y *= t; }
	void operator/=(T t) { x /= t; y /= t; }
};

int main() {
	using pt = point<long double>;
	int q;
	cin >> q;
	REP(i, q) {
		int x0, y0, x1, y1, x2, y2, x3, y3;
		cin >> x0 >> y0 >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
		pt p0(x0, y0), p1(x1, y1), p2(x2, y2), p3(x3, y3);
		if (pt::isParallel(p0, p1, p2, p3)) {
			put(2);
			continue;
		}
		if (pt::isOrthogonal(p0, p1, p2, p3)) {
			put(1);
			continue;
		}
		put(0);
	}
	return 0;
}


Measured memory_bytes: 3104