#include <bits/stdc++.h>
using namespace std;
typedef complex<double> P;

const double eps = 1e-8;

namespace std {
  bool operator < (const P &a, const P &b) {
    return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
  }
}

double dot(P a, P b) {
  return a.real()*b.real() + a.imag()*b.imag();
}

double cross(P a, P b) {
  return a.real()*b.imag() - a.imag()*b.real();
}

int ccw(P p, P a, P b) {
  a -= p;
  b -= p;
  if(cross(a, b) > 0) return 1;
  if(cross(a, b) < 0) return -1;
  if(dot(a, b) < 0) return 2;
  if(norm(b) > norm(a)) return -2;
  return 0;
}

bool isIntersect(P a1, P a2, P b1, P b2) {
  return ( ccw(a1, a2, b1) * ccw(a1, a2, b2) <= 0 &&
           ccw(b1, b2, a1) * ccw(b1, b2, a2) <= 0 );
}

P getCrossP(P a1, P a2, P b1, P b2) {
  P a = a2 - a1;
  P b = b2 - b1;
  return a1 + a * cross(b, b1 - a1)/cross(b, a);
}

const int D[10][7] = {
  {2,2,2,2,0,0,0},
  {1,1,0,0,0,0,0},
  {1,2,2,2,2,1,0},
  {1,2,3,2,1,1,0},
  {1,2,3,1,1,0,0},
  {1,2,2,2,2,1,0},
  {1,2,3,2,2,2,0},
  {1,2,2,1,0,0,0},
  {2,2,2,2,3,3,0},
  {1,3,2,2,2,0,0}
};

typedef vector<vector<int> > Graph;

Graph segmentArrangement(const vector<P> &s1, const vector<P> &s2,
                         vector<P> &ps) {
  int m = s1.size();
  for(int i = 0; i < m; ++i) {
    ps.push_back(s1[i]);
    ps.push_back(s2[i]);
    for(int j = i+1; j < m; ++j) {
      if(cross(s1[i] - s2[i], s1[j] - s2[j]) == 0.0) continue;
      if(!isIntersect(s1[i], s2[i], s1[j], s2[j])) continue;
      ps.push_back(getCrossP(s1[i], s2[i], s1[j], s2[j]));
    }
  }
  sort(ps.begin(), ps.end());
  ps.erase(unique(ps.begin(), ps.end()), ps.end());

  int n = ps.size();
  Graph g(n);
  for(int i = 0; i < m; ++i) {
    vector<pair<double, int> > v;
    for(int j = 0; j < n; ++j) {
      if(ps[j] == s1[i] || ps[j] == s2[i] || !ccw(s1[i], s2[i], ps[j])) {
        v.push_back(make_pair(norm(s1[i] - ps[j]), j));
      }
    }
    sort(v.begin(), v.end());
    for(int j = 0; j+1 < v.size(); ++j) {
      int a = v[j].second, b = v[j+1].second;
      g[a].push_back(b);
      g[b].push_back(a);
    }
  }
  return g;
}

void dfs(int v, vector<int> &vis, vector<int> &deg, vector<int> &vs, const Graph &g) {
  vis[v] = true;
  vs.push_back(v);
  deg.push_back(g[v].size());
  for(int i = 0; i < g[v].size(); ++i) {
    int nv = g[v][i];
    if(vis[nv]) continue;
    dfs(nv, vis, deg, vs, g);
  }
}


int main() {
  map<vector<int>, int> digit;
  for(int i = 0; i < 10; ++i) {
    vector<int> v;
    for(int j = 0; D[i][j]; ++j) {
      v.push_back(D[i][j]);
    }
    sort(v.begin(), v.end());
    digit[v] = i;
  }

  for(int n; cin >> n && n; ) {
    vector<P> a(n), b(n), ps;
    for(int i = 0; i < n; ++i) {
      cin >> a[i].real() >> a[i].imag() >> b[i].real() >> b[i].imag();
    }
    Graph G = segmentArrangement(a, b, ps);
    int V = G.size();
    vector<int> res(10);
    vector<int> vis(V);
    for(int v = 0; v < V; ++v) {
      if(vis[v]) continue;
      vector<int> deg;
      vector<int> vs;
      dfs(v, vis, deg, vs, G);
      sort(deg.begin(), deg.end());
      if(!digit.count(deg)) continue;
      if(digit[deg] == 5) {
        for(int i = 0; i < vs.size(); ++i) {
          int s = vs[i];
          if(G[s].size() == 1) {
            int t = G[s][0];
            int u = G[t][0] == s ? G[t][1] : G[t][0];
            P a = ps[s];
            P b = ps[t];
            P c = ps[u];
            if(cross(b-a, c-b) > 0) res[5]++;
            else res[2]++;
            break;
          }
        }
      } else {
        res[digit[deg]]++;
      }
    }
    for(int i = 0; i < 10; ++i) {
      if(i) cout << " ";
      cout << res[i];
    }
    cout << endl;
  }
  return 0;
}

Measured memory_bytes: 1416