#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int mod = 1e9 + 7;
const int inf = (1 << 30) - 1;
const ll infll = (1LL << 61) - 1;

using Real = double;
using Point = complex<Real>;
const Real Pi = acos(-1), EPS = 1e-9;
inline bool eq(Real a, Real b) { return fabs(a - b) < EPS; }

//scalar
Point operator*(const Point &p, const Real &c)
{
    return Point(c * real(p), c * imag(p));
}

//add
Point operator+(const Point &p, const Point &q)
{
    return Point(real(p) + real(q), imag(p) + imag(q));
}

Point operator-(const Point &p, const Point &q)
{
    return Point(real(p) - real(q), imag(p) - imag(q));
}
//equal
bool operator==(const Point &p, const Point &q)
{
    return (real(p) == real(q)) && (imag(p) == imag(q));
}

Real radian_to_degree(Real r)
{
    return (r * 180.0 / Pi);
}

Real degree_to_radian(Real d)
{
    return (d * Pi / 180.0);
}

//rotate
Point rot(Real theta, const Point &p)
{
    return Point(cos(theta) * p.real() - sin(theta) * p.imag(), sin(theta) * p.real() + cos(theta) * p.imag());
}

//norm
Real norm(Point const &p)
{
    return (real(p) * real(p) + imag(p) * imag(p));
}

//argumant [0, 2 * Pi)
Real arg(Point const &p)
{
    Real a = atan2(imag(p), real(p));
    if (a < 0)
        a = fabs(a) + Pi;
    return a;
}

//input
istream &operator>>(istream &is, Point &p)
{
    Real a, b;
    is >> a >> b;
    p = Point(a, b);
    return is;
}

//output
ostream &operator<<(ostream &os, Point &p)
{
    os << fixed << setprecision(10) << p.real() << " " << p.imag();
}

// a line given two points
struct Line
{
    Point a, b;
    Line() = default;

    Line(Point a, Point b) : a(a), b(b) {}

    // Ax + By = C
    Line(Real A, Real B, Real C)
    {
        if (eq(A, 0))
            a = Point(0, C / B), b = Point(1, C / B);
        else if (eq(B, 0))
            b = Point(C / A, 0), b = Point(C / A, 1);
        else
            a = Point(0, C / B), b = Point(C / A, 0);
    }

    friend istream &operator>>(istream &is, Line &a)
    {
        return is >> a.a >> a.b;
    }

    friend ostream &operator<<(ostream &os, Line &p)
    {
        return os << p.a << " to " << p.b;
    }
};

using Points = vector<Point>;
using Polygon = vector<Point>;
using Lines = vector<Line>;

Real dot(const Point &p, const Point &q)
{
    return (real(p) * real(q) + imag(p) * imag(q));
}

// regard z - component is zero
Real cross(const Point &p, const Point &q)
{
    return real(p) * imag(q) - imag(p) * real(q);
}

//For given three points p1,p2,p, find the projection point x of p onto p1p2.
Point projection(const Line &l, const Point &p)
{
    double t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b); // direction vector
    return l.a + (l.a - l.b) * t;
}

//For given three points p1,p2,p, find the reflection point x of p onto p1p2.
Point reflection(const Line &l, const Point &p)
{
    return p + (projection(l, p) - p) * 2.0;
}

int Counter_Clockwise(const Point &a, Point b, Point c)
{
    // a is standard
    b = b - a, c = c - a;
    if (cross(b, c) > EPS)
        return +1; // counter clockwise
    if (cross(b, c) < -EPS)
        return -1; // clockwise
    if (dot(b, c) < 0)
        return +2; // c--a--b on line
    if (norm(b) < norm(c))
        return -2; // a--b--c on line
    return 0;      // c on segment a-b
}

// two lines are parallel
bool Parallel(const Line &L1, const Line &L2)
{
    return eq(cross(L1.b - L1.a, L2.b - L2.a), 0.0);
}

// two lines are orthogonal
bool Orthogonal(const Line &L1, const Line &L2)
{
    return eq(dot(L1.b - L1.a, L2.b - L2.a), 0.0);
}

int main()
{
    int Q;
    cin >> Q;
    Line l, r;
    for (int i = 0; i < Q; i++)
    {
        cin >> l >> r;
        if (Parallel(l, r) == true)
        {
            cout << "2\n";
        }
        else if (Orthogonal(l, r) == true)
        {
            cout << "1\n";
        }
        else
        {
            cout << "0\n";
        }
    }
}


Measured memory_bytes: 3240