// Arup Guha
// 3/21/2021
// Solution to 2021 UCF HS Contest Problem: Molecular Mole

import java.util.*;

public class mole {

	public static void main(String[] args) {
	
		// Get # of cases.
		Scanner stdin = new Scanner(System.in);
		int nC = stdin.nextInt();
		
		// Process cases.
		for (int loop=0; loop<nC; loop++) {
		
			int n = stdin.nextInt();
			ray[] list = new ray[n];
			
			// Read the rays.
			for (int i=0; i<n; i++) {
				int x = stdin.nextInt();
				int y = stdin.nextInt();
				int dx = stdin.nextInt();
				int dy = stdin.nextInt();
				double mag = Math.sqrt(dx*dx+dy*dy);
				pt s = new pt(x, y);
				pt dir = new pt(dx/mag, dy/mag);
				list[i] = new ray(s, dir);
			}
			
			// Stores which dot is which, since collisions are like trading places.
			// perm[i] will store where original dot i is now. inv stores the inverse of perm.
			int[] perm = new int[n];
			for (int i=0; i<n; i++) perm[i] = i;
			
			// Stores the final result.
			int[] res = new int[n];
			
			// Calculate all collisions originally.
			ArrayList<event> collisions = new ArrayList<event>();
			for (int i=0; i<n; i++) {
				for (int j=i+1; j<n; j++) {
					Double mytime = list[i].collisionTime(list[j]);
					if (mytime != null)
						collisions.add(new event(i, j, mytime));
				}
			}
			
			// Sort by time.
			Collections.sort(collisions);
			
			// Go through the collisions.
			for (int i=0; i<collisions.size(); i++) {
				
				// We're supposed to stop here.
				if (collisions.get(i).t > 1000000) break;
				
				int loc1 = collisions.get(i).a;
				int loc2 = collisions.get(i).b;
					
				// Add a collision.
				res[perm[loc1]]++;
				res[perm[loc2]]++;
				
				// swap places. perm[loc1] perm[loc2]
				int tmp = perm[loc1];
				perm[loc1] = perm[loc2];
				perm[loc2] = tmp;
			}
			
			// Ta da!
			for (int i=0; i<n; i++)
				System.out.println(res[i]);
		}
	}
}

// An event is a collision between "original" particles a and b at time t.
class event implements Comparable<event> {

	public int a;
	public int b;
	public double t;
	
	public event(int mya, int myb, double myt) {
		a = mya;
		b = myb;
		t = myt;
	}
	
	// Sorts by time.
	public int compareTo(event other) {
		if (t < other.t) return -1;
		if (t > other.t) return 1;
		return Math.min(a,b) - Math.min(other.a, other.b);
	}
}

class pt {

	public double x;
	public double y;
	
	public pt(double myx, double myy) {
		x = myx;
		y = myy;
	}
}

class ray {

	public pt start;
	public pt dir;
	
	public ray(pt s, pt d) {
		start = s;
		dir = d;
	}
	
	public Double collisionTime(ray other) {
	
		double dDirX = dir.x - other.dir.x;
		double dDirY = dir.y - other.dir.y;
		
		// Assumes two starting points are always different.
		if (Math.abs(dDirX) < 1e-9 && Math.abs(dDirY) < 1e-9) return null;
		
		// Normal case.
		if (Math.abs(dDirX) > 1e-9 && Math.abs(dDirY) > 1e-9) {
		
			// Get both possible answers, using 1 parameter, not two.
			double ans1 = (other.start.x - start.x)/dDirX;
			double ans2 = (other.start.y - start.y)/dDirY;
		
			// The answers have to match to be a real collision, and be positive.
			if (Math.abs(ans1-ans2) > 1e-9 || ans1 < 0 || ans2 < 0) return null;
			
			// This is the answer in this case.
			return ans1;
		}
		
		// x vectors match.
		if (Math.abs(dDirX) < 1e-9) {
			if (Math.abs(other.start.x - start.x) > 1e-9) return null;
			double ans2 = (other.start.y - start.y)/dDirY;
			if (ans2 < 0) return null;
			return ans2;
		}
		
		// Must have y's match.
		if (Math.abs(other.start.y - start.y) > 1e-9) return null;
		double ans1 = (other.start.x - start.x)/dDirX;
		if (ans1 < 0) return null;
		return ans1;
	}
}