#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include<vector>
#include<cstring>
#include<set>
#include <cstdio>
#include<queue>
#include<map>
#define WHITE 0
#define GRAY  1
#define BLACK 2
#define endl '\n'
#define forup(i,a,n) for( int i =a; i < n; i++)
#define llforup(i,a,n) for( ll i =a; i < n; i++)
#define fordown(i,a,n) for( int i =a; i >= n; i--)
#define fornot(i,a,n) for( int i=a;!n;i++)
#define mod  (ll)(1e9+7)
#define putnum(a) printf("%d\n",a)
using namespace std;
typedef long long ll;
inline int readnum()
{
	int p, data = 0; char ch = 0;
	while ((ch != '-') &&( ch < '0' || ch>'9') )//注意运算优先级，逻辑与大于逻辑非
		ch = getchar();//相当于正则表达式的搜索，跳过不需要的字符
	if (ch == '-')
		p = -1, ch = getchar();//不能与if平行放置，不懂为什么，可能是bug
	else p = 1;
	while (ch >= '0' && ch <= '9') data = data * 10 + ch - '0', ch = getchar();//搜索需要的字符
	return data * p;
}
inline int ReadPossitive()
{
	char ch; int data = 0;
	ch = getchar();
	while (ch == ' ' || ch == '\n')ch = getchar();
	while (ch != ' ' && ch != '\n' && ch != EOF)
	{
		data = data * 10 + ch - '0';
		ch = getchar();
	}
	return data;
}
//并查集模板
class DisjointSet {
private:
	vector<int>rank, parent;
public:
	DisjointSet(){}
	DisjointSet(int size)
	{
		rank.resize(size, 0);//默认初始化为0，养成习惯写完整
		parent.resize(size, 0);
		forup(i, 0, size)MakeSet(i);
	}
	void MakeSet(int x)
	{
		parent[x] = x;
		rank[x] = 0;
	}
	bool same(int x, int y)
	{
		return Findroot(x) == Findroot(y);
	}
	void unite(int x, int y)
	{
		link(Findroot(x), Findroot(y));
	}
	inline int Findroot(int x)
	{
		while (x != parent[x])
		{
			x = parent[x];
		}
		return x;
	}
	void link(int rootx, int rooty)
	{
		if (rank[rootx] < rank[rooty])parent[rootx] = parent[rooty];
		else
		{
			parent[rooty] = parent[rootx];
			if (rank[rootx] == rank[rooty])
				rank[rootx]++;
		}
	}
};

//计算几何模板
#define EPS (1e-10)
#define equals(a,b) (fabs((a)-(b))<EPS)//保留整数0
class Point {
public:
	double x, y;
public:
	Point() {};
	Point(double x,double y):x(x),y(y){}
	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 *(double a) { return Point(a * x, a * y); }
	Point operator /(double a) { return Point(x / a, y / a); }
	inline double abs() { return sqrt(norm()); }
	inline double norm() { return x * x + y * y; }
	bool operator <(const Point& p)const {
		return x != p.x ? x < p.x : y < p.y;
	}
	bool operator ==(const Point& p)const {
		return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
	}
};
class Vector :public Point{//公有继承
public:
	double dot(Point a, Point b)//点乘
	{
		return a.x * b.x + a.y * b.y;
	}
	double cross(Point a, Point b)//叉乘
	{
		return a.x * b.y - a.y * b.x;
	}
};
class Line{
public:
	Point p1, p2;
public:
	Line() {};
	Line(int p1x, int p1y, int p2x, int p2y)
	{
		p1.x = p1x; p1.y = p1y;
		p2.x = p2x; p2.y = p2y;
	}
};
class LineOperation :public Vector{
public:	
	LineOperation() {};
	bool isOrthogonal(Line s1, Line s2)
	{
		return equals(dot(s1.p2-s1.p1, s2.p2 - s2.p1), 0.0);//操作符重载的返回值的内存分配机制尚不可知，似乎返回值没有分配内存，dot的参数不能用引用，否则报错。
	}
	bool isParallel(Line s1, Line s2)
	{
		return equals(cross(s1.p2 - s1.p1, s2.p2 - s2.p1), 0.0);//外积判断平行，内积判断垂直。
	}
};
//E-mail 374656045@qq.com

class solve {
private:
	int n;
public://采用邻接表建图,带权无向图
	solve()
	{
		n = ReadPossitive();
		int x1, y1, x2, y2, x3, y3, x4, y4;
		LineOperation op;
		forup(i, 0, n)
		{
			x1 = readnum(); y1 = readnum();
			x2 = readnum(); y2 = readnum();
			x3 = readnum(); y3 = readnum();
			x4 = readnum(); y4 = readnum();
			Line s1(x1, y1, x2, y2), s2(x3, y3, x4, y4);
			if (op.isParallel(s1, s2))putnum(2);
			else if (op.isOrthogonal(s1, s2))putnum(1);
			else putnum(0);
		}
	}
	
};
int main(void)
{
	ios_base::sync_with_stdio(0); cin.tie(0);//慎用，cin和scanf混用会导致非MSC++WA
#ifdef DEBUG
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	solve solution;
#ifdef DEBUG
	fclose(stdin);//关闭文件 
	fclose(stdout);//关闭文件 
#endif
	return 0;

}




Measured memory_bytes: 3248