#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const double EPS = 1e-8;
const double INF = 1e12;
typedef complex<double> P;
namespace std{
	bool operator < (const P& a, const P& b){
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
}
double cross(const P& a, const P& b){
	return imag(conj(a)*b);
}
double dot(const P& a, const P& b){
	return real(conj(a)*b);
}

struct L : public vector<P>{
	L(){}
	L(const P &a, const P &b){
		push_back(a); push_back(b);
	}
};

struct C{
	P p; double r;
	C(const P &p, double r) : p(p), r(r){}
};

int ccw(P a, P b, P c){
	b -= a; c -= a;
	if(cross(b, c) > 0)   return +1;       // counter clockwise
	if(cross(b, c) < 0)   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;
}

bool intersectLL(const L &l, const L &m){
	return abs(cross(l[1] - l[0], m[1] - m[0])) > EPS || // non-parallel
		abs(cross(l[1] - l[0], m[0] - l[0])) < EPS;   // same line
}
bool intersectLS(const L &l, const L &s){
	return cross(l[1] - l[0], s[0] - l[0])*       // s[0] is left of l
		cross(l[1] - l[0], s[1] - l[0]) < EPS; // s[1] is right of l
}
bool intersectLP(const L &l, const P &p){
	return abs(cross(l[1] - p, l[0] - p)) < EPS;
}
bool intersectSS(const L &s, const L &t){
	return ccw(s[0], s[1], t[0])*ccw(s[0], s[1], t[1]) <= 0 &&
		ccw(t[0], t[1], s[0])*ccw(t[0], t[1], s[1]) <= 0;
}
bool intersectSP(const L &s, const P &p){
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS; // triangle inequality
}

struct UnionFind{
	vector<int> par;
	int cnt;
	UnionFind(int size_) : par(size_, -1), cnt(size_){}
	void unite(int x, int y){
		if((x = find(x)) != (y = find(y))){
			if(par[y] < par[x]) swap(x, y);
			par[x] += par[y]; par[y] = x; cnt--;
		}
	}
	bool same(int x, int y){ return find(x) == find(y); }
	int find(int x){ return par[x] < 0 ? x : par[x] = find(par[x]); }
	int size(int x){ return -par[find(x)]; }
	int size(){ return cnt; }
};

L l[1000];
vector<int> G[1000];
map<vector<int>, int> m;

int check(vector<int> g){
	if(g.size() == 0) return -1;
	if(g.size() == 1) return 1;
	if(g.size() == 2) return -1;

	for(int i = 0; i < g.size(); i++){
		P v1 = l[g[i]][0] - l[g[i]][1];
		for(int j = i + 1; j < g.size(); j++){
			if(i == j) continue;
			P v2 = l[g[j]][0] - l[g[j]][1];
			double d = dot(v1, v2);
			double c = cross(v1, v2);
			if(d < EPS || c < EPS) continue;
			return -1;
		}
	}

	vector<int> num(6);
	for(int i = 0; i < g.size(); i++){
		int same = 0, mid = 0;
		L l1 = l[g[i]];
		for(int j = 0; j < g.size(); j++){
			if(i == j) continue;
			L l2 = l[g[j]];
			if(l1[0] == l2[0] || l1[1] == l2[1] || l1[0] == l2[1] || l1[1] == l2[0]){
				same++;
			}
			else if(intersectSP(l2, l1[0]) || intersectSP(l2, l1[1])){
				mid++;
			}
		}
		if(same == 0 && mid == 0) num[0]++;
		if(same == 1 && mid == 0) num[1]++;
		if(same == 2 && mid == 0) num[2]++;
		if(same == 1 && mid == 1) num[3]++;
		if(same == 0 && mid == 2) num[4]++;
		if(same == 0 && mid == 1) num[5]++;
	}

	int ret = -1;
	if(m.count(num)) ret = m[num];

	if(ret == 2){
		for(int i = 0; i < g.size(); i++){
			int same = 0, mid = 0;
			L l1 = l[g[i]];
			L ll;
			P p;
			for(int j = 0; j < g.size(); j++){
				if(i == j) continue;
				L l2 = l[g[j]];
				if(l1[0] == l2[0] || l1[1] == l2[1] || l1[0] == l2[1] || l1[1] == l2[0]){
					same++;
					if(l1[0] == l2[0] || l1[0] == l2[1]) p = l1[0];
					else p = l1[1];
					ll = l2;
				}
				else if(intersectSP(l2, l1[0]) || intersectSP(l2, l1[1])){
					mid++;
				}
			}
			if(same == 1 && mid == 0){
				P p1 = l1[0], p2 = l1[1];
				if(p2 == p) swap(p1, p2);
				P v1 = p2 - p1;
				p1 = ll[0], p2 = ll[1];
				if(p2 == p) swap(p1, p2);
				P v2 = p2 - p1;

				double c = cross(v1, v2);
				if(c < 0) ret = 5;
			}
		}
	}
	return ret;
}

int main(){
	cin.tie(0);
	ios::sync_with_stdio(false);
#ifdef LOCAL
	std::ifstream in("in");
	std::cin.rdbuf(in.rdbuf());
#endif

	m[{ 0, 0, 4, 0, 0, 0 }] = 0;
	m[{ 1, 0, 4, 0, 0, 0 }] = 1;
	m[{ 0, 2, 3, 0, 0, 0 }] = 2;
	m[{ 0, 2, 1, 0, 0, 1 }] = 3;
	m[{ 1, 1, 0, 1, 0, 0 }] = 4;
	//m[{ 0, 2, 3, 0, 0, 0 }] = 5;
	m[{ 0, 1, 3, 1, 0, 0 }] = 6;
	m[{ 0, 2, 1, 0, 0, 0 }] = 7;
	m[{ 0, 0, 4, 0, 1, 0 }] = 8;
	m[{ 0, 1, 2, 1, 0, 0 }] = 9;

	int N;
	while(cin >> N, N){
		for(int i = 0; i < N; i++){
			double x1, y1, x2, y2;
			cin >> x1 >> y1 >> x2 >> y2;
			l[i] = L(P(x1, y1), P(x2, y2));
		}

		for(int i = 0; i < N; i++){
			G[i].clear();
		}

		UnionFind uf(N);
		for(int i = 0; i < N; i++){
			for(int j = i + 1; j < N; j++){
				if(intersectSS(l[i], l[j])) uf.unite(i, j);
			}
		}
		for(int i = 0; i < N; i++){
			int p = uf.find(i);
			G[p].push_back(i);
		}

		int ans[10] = { 0 };
		for(int i = 0; i < N; i++){
			int res = check(G[i]);
			if(res != -1) ans[res]++;
		}

		for(int i = 0; i < 10; i++){
			cout << ans[i] << (i != 9 ? " " : "");
		}
		cout << endl;
	}


}

Measured memory_bytes: 3436