Problem:
串刺し
xy 平面上に
N
本の線分が配置されている．
あなたは
(0,1]
の一様乱数から 2 つの実数
a
,
b
を独立に取り出す．
ax+by=1
で表される直線と共有点を持つ線分の個数が，あなたのスコアとなる．
0
以上
N
以下のそれぞれのスコア
i
について，そのスコアが得られる確率を
p
i
とする．ここで
p
i
は有理数となることを示すことができる．
p
i
が既約分数
y
i
/x
i
で表されるとき，
y
i
≡ a
i
× x
i
mod
1000000007
となる最小の
0
以上の整数
a
i
を求めよ．与えられる入力に対し，そのような
a
i
が存在することが保証される．
Input
入力は 100 個以下のデータセットからなる． 各データセットは次の形式で表される．
N
x
11
y
11
x
12
y
12
...
x
N1
y
N1
x
N2
y
N2
N
(
1 ≤ N ≤ 50
) は線分の個数を表す．続く
N
行にはそれぞれ線分の端点の
x
座標と
y
座標を表す 4 つの整数
x
i1
,
y
i1
,
x
i2
,
y
i2
が与えられ，
i
番目の線分の端点の座標が
(x
i1
, y
i1
)
および
(x
i2
, y
i2
)
であることを表す．いずれの座標値も
1
以上
100
以下である．また，
(x
i1
,y
i1
) ≠ (x
i2
,y
i2
)
であることが保証される．
入力の終わりは 1 つのゼロからなる行で表される．
Output
各データセットについて，
0
以上
N
以下のそれぞれのスコアについてそのスコアが得られる確率を求め，問題文で定義された
a
i
を空白区切りで出力せよ．
Sample Input
1
1 1 2 2
3
1 4 7 3
5 4 5 2
4 5 2 1
5
31 41 5 92
65 35 89 7
93 23 84 62
84 62 93 23
64 33 83 2
0
Output for the Sample Input
625000005 375000003
306211183 463800440 279241779 950746613
569549369 651563025 897288531 7049563 987270468 887279073

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using uint = unsigned int;
#define rep(i, n) for (int i = 0; i < n; i++)
#define all(v) v.begin(), v.end()
template <class T, class U>
inline bool chmax(T &a, U b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
template <class T, class U>
inline bool chmin(T &a, U b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template <class T>
inline void compress(vector<T> &a) {
    sort(a.begin(), a.end());
    a.erase(unique(a.begin(), a.end()), a.end());
}
struct Rational {
    __int128_t N, D;
    Rational() = default;
    Rational(__int128_t x) : N(x), D(1) {}
    Rational(__int128_t n, __int128_t d) : N(n), D(d) {}
    Rational &operator+=(const Rational &p) {
        tie(N, D) = make_pair(N * p.D + p.N * D, D * p.D);
        check();
        return *this;
    }
    Rational &operator-=(const Rational &p) {
        tie(N, D) = make_pair(N * p.D - p.N * D, D * p.D);
        check();
        return *this;
    }
    Rational &operator*=(const Rational &p) {
        N *= p.N;
        D *= p.D;
        check();
        return *this;
    }
    Rational &operator/=(const Rational &p) {
        N *= p.D;
        D *= p.N;
        if (D < 0) N = -N, D = -D;
        check();
        return *this;
    }
    Rational operator-() const { return Rational(-N, D); }
    Rational operator+(const Rational &p) const { return Rational(*this) += p; }
    Rational operator-(const Rational &p) const { return Rational(*this) -= p; }
    Rational operator*(const Rational &p) const { return Rational(*this) *= p; }
    Rational operator/(const Rational &p) const { return Rational(*this) /= p; }
    bool operator==(const Rational &p) const { return __int128_t(N) * p.D == __int128_t(D) * p.N; }
    bool operator<(const Rational &p) const { return __int128_t(N) * p.D < __int128_t(D) * p.N; }
    bool operator<=(const Rational &p) const { return __int128_t(N) * p.D <= __int128_t(D) * p.N; }
    __int128_t numerator() { return N; }
    __int128_t denominator() { return D; }
    void check() {
        if (D < 0) {
            D = -D;
            N = -N;
        }
    }
};

template <int modulo>
struct modint {
    int x;
    modint() : x(0) {}
    modint(int64_t y) : x(y >= 0 ? y % modulo : (modulo - (-y) % modulo) % modulo) {}
    modint &operator+=(const modint &p) {
        if ((x += p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator-=(const modint &p) {
        if ((x += modulo - p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator*=(const modint &p) {
        x = (int)(1LL * x * p.x % modulo);
        return *this;
    }
    modint &operator/=(const modint &p) {
        *this *= p.inv();
        return *this;
    }
    modint operator-() const { return modint(-x); }
    modint operator+(const modint &p) const { return modint(*this) += p; }
    modint operator-(const modint &p) const { return modint(*this) -= p; }
    modint operator*(const modint &p) const { return modint(*this) *= p; }
    modint operator/(const modint &p) const { return modint(*this) /= p; }
    bool operator==(const modint &p) const { return x == p.x; }
    bool operator!=(const modint &p) const { return x != p.x; }
    modint inv() const {
        int a = x, b = modulo, u = 1, v = 0, t;
        while (b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return modint(u);
    }
    modint pow(int64_t n) const {
        modint ret(1), mul(x);
        while (n > 0) {
            if (n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }
    friend ostream &operator<<(ostream &os, const modint &p) { return os << p.x; }
    friend istream &operator>>(istream &is, modint &a) {
        int64_t t;
        is >> t;
        a = modint<modulo>(t);
        return (is);
    }
    int val() const { return x; }
    static constexpr int mod() { return modulo; }
    static constexpr int half() { return (modulo + 1) >> 1; }
};
using mint = modint<1000000007>;
struct Line {
    ll A, B;
};
mint RtoM(Rational a) { return mint(a.numerator()) / a.denominator(); }
Rational getY_R(Line l, Rational X) {
    auto [A, B] = l;
    if (Rational(1) < X * B) return 0;
    return (Rational(1) / A * (Rational(1) - X * B));
}
mint getY(Line l, Rational X) {
    auto [A, B] = l;
    if (Rational(1) < X * B) return 0;
    return (mint(1) / A * RtoM(Rational(1) - X * B));
}
struct Point {
    Rational x, y;
};
bool isParallel(Line l, Line m) {
    auto [A, B] = l;
    auto [C, D] = m;
    return A * D == B * C;
}
Rational crosspointx(Line l, Line m) {
    auto [A, B] = l;
    auto [C, D] = m;
    Rational res(A - C, A * D - B * C);
    res.check();
    return res;
}
void solve() {
    int n;
    cin >> n;
    if (n == 0) exit(0);
    vector es(n, vector<Line>(2));
    vector<Line> ES;
    rep(i, n) {
        ll x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        Line l1{y1, x1};
        Line l2{y2, x2};
        es[i] = {l1, l2};
        ES.push_back(l1);
        ES.push_back(l2);
    }
    vector<Rational> xs{0, 1};
    rep(i, ES.size()) {
        xs.push_back(Rational(1, ES[i].B));
        rep(j, i) {
            if (isParallel(ES[i], ES[j])) continue;
            xs.push_back(crosspointx(ES[i], ES[j]));
            if (xs.back() < Rational(0))
                xs.pop_back();
            else if (Rational(1) < xs.back())
                xs.pop_back();
        }
    }
    compress(xs);
    vector<mint> ans(n + 1);
    rep(xid, xs.size() - 1) {
        // cout << (ll)xs[xid].numerator() << "/" << (ll)xs[xid].denominator() << endl;
        Rational dx = xs[xid + 1] - xs[xid];
        auto mint_dx = mint(dx.numerator()) / dx.denominator();
        vector<pair<Line, int>> segs;
        rep(i, n) {
            segs.push_back({es[i][0], i});
            segs.push_back({es[i][1], i});
        }
        sort(all(segs), [&](auto L, auto M) {
            if (isParallel(L.first, M.first)) {
                return M.first.A < L.first.A;
            }
            if (L.first.A == M.first.A) return M.first.B < L.first.B;
            Rational cx = crosspointx(L.first, M.first);
            if (Rational(0) <= cx && cx <= xs[xid]) {
                return L.first.A < M.first.A;

            } else {
                return M.first.A < L.first.A;
            }
        });
        int cnt = 0;
        mint lyl = 0, lyr = 0;
        vector<bool> appear(n);
        for (auto [seg, i] : segs) {
            mint yl = getY(seg, xs[xid]);
            mint yr = getY(seg, xs[xid + 1]);
            ans[cnt] += (yl + yr - lyl - lyr) * mint_dx * mint::half();
            lyl = yl, lyr = yr;
            if (!appear[i]) {
                appear[i] = true;
                cnt++;
            } else
                cnt--;
        }
    }
    ans[0] = mint(1) - reduce(ans.begin() + 1, ans.end());
    rep(i,n+1)cout<<ans[i]<<" \n"[i==n];
}
int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int t = 1;
    // cin >> t;
    while (t) solve();
}
accuracy: 1
time_ms: 890
memory_kb: 3832
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using uint = unsigned int;
#define rep(i, n) for (int i = 0; i < n; i++)
#define all(v) v.begin(), v.end()
template <class T, class U>
inline bool chmax(T &a, U b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
template <class T, class U>
inline bool chmin(T &a, U b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template <class T>
inline void compress(vector<T> &a) {
    sort(a.begin(), a.end());
    a.erase(unique(a.begin(), a.end()), a.end());
}
template <class T>
T rand(T l, T r) {
    static mt19937 mt(random_device{}());
    // [l, r)
    if constexpr (is_integral_v<T>) {
        return uniform_int_distribution<T>(l, r - 1)(mt);
    } else if constexpr (is_floating_point_v<T>) {
        return uniform_real_distribution<T>(l, r)(mt);
    }
}
constexpr int INF = 1001001001;
constexpr ll llINF = 3000000000000000010;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using pbds_set = tree<ll, null_type, less<ll>, rb_tree_tag, tree_order_statistics_node_update>;
using pbds_mset = tree<ll, null_type, less_equal<ll>, rb_tree_tag, tree_order_statistics_node_update>;
using pbds_umap = gp_hash_table<int, int>;
using pbds_trie = trie<string, null_type, trie_string_access_traits<>, pat_trie_tag, trie_prefix_search_node_update>;
struct linear_sieve {
    vector<int> least_factor, prime_list;
    linear_sieve(int n) : least_factor(n + 1, 0) {
        for (int i = 2; i <= n; i++) {
            if (least_factor[i] == 0) {
                least_factor[i] = i;
                prime_list.push_back(i);
            }
            for (int p : prime_list) {
                if (ll(i) * p > n || p > least_factor[i]) break;
                least_factor[i * p] = p;
            }
        }
    }
};
template <int modulo>
struct modint {
    int x;
    modint() : x(0) {}
    modint(int64_t y) : x(y >= 0 ? y % modulo : (modulo - (-y) % modulo) % modulo) {}
    modint &operator+=(const modint &p) {
        if ((x += p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator-=(const modint &p) {
        if ((x += modulo - p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator*=(const modint &p) {
        x = (int)(1LL * x * p.x % modulo);
        return *this;
    }
    modint &operator/=(const modint &p) {
        *this *= p.inv();
        return *this;
    }
    modint operator-() const { return modint(-x); }
    modint operator+(const modint &p) const { return modint(*this) += p; }
    modint operator-(const modint &p) const { return modint(*this) -= p; }
    modint operator*(const modint &p) const { return modint(*this) *= p; }
    modint operator/(const modint &p) const { return modint(*this) /= p; }
    bool operator==(const modint &p) const { return x == p.x; }
    bool operator!=(const modint &p) const { return x != p.x; }
    modint inv() const {
        int a = x, b = modulo, u = 1, v = 0, t;
        while (b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return modint(u);
    }
    modint pow(int64_t n) const {
        modint ret(1), mul(x);
        while (n > 0) {
            if (n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }
    friend ostream &operator<<(ostream &os, const modint &p) { return os << p.x; }
    friend istream &operator>>(istream &is, modint &a) {
        int64_t t;
        is >> t;
        a = modint<modulo>(t);
        return (is);
    }
    int val() const { return x; }
    static constexpr int mod() { return modulo; }
    static constexpr int half() { return (modulo + 1) >> 1; }
};
template <class T>
T gcd128(T a, T b) {
    if (b == 0) return a;
    return gcd128(b, a % b);
}
ll extgcd(ll a, ll b, ll &x, ll &y) {
    // ax+by=gcd(|a|,|b|)
    if (a < 0 || b < 0) {
        ll d = extgcd(abs(a), abs(b), x, y);
        if (a < 0) x = -x;
        if (b < 0) y = -y;
        return d;
    }
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    ll d = extgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
template <typename T>
struct Binomial {
    vector<T> inv, fact, factinv;
    Binomial(int n) {
        inv.resize(n + 1);
        fact.resize(n + 1);
        factinv.resize(n + 1);
        inv[0] = fact[0] = factinv[0] = 1;
        for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i;
        factinv[n] = fact[n].inv();
        inv[n] = fact[n - 1] * factinv[n];
        for (int i = n - 1; i >= 1; i--) {
            factinv[i] = factinv[i + 1] * (i + 1);
            inv[i] = fact[i - 1] * factinv[i];
        }
    }
    T C(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r] * factinv[r];
    }
    T P(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r];
    }
    T H(int n, int r) {
        if (n == 0 && r == 0) return 1;
        if (n < 0 || r < 0) return 0;
        return r == 0 ? 1 : C(n + r - 1, r);
    }
};
struct Rational {
    __int128_t N, D;
    Rational() = default;
    Rational(__int128_t x) : N(x), D(1) {}
    Rational(__int128_t n, __int128_t d) : N(n), D(d) {}
    Rational &operator+=(const Rational &p) {
        tie(N, D) = make_pair(N * p.D + p.N * D, D * p.D);
        check();
        return *this;
    }
    Rational &operator-=(const Rational &p) {
        tie(N, D) = make_pair(N * p.D - p.N * D, D * p.D);
        check();
        return *this;
    }
    Rational &operator*=(const Rational &p) {
        N *= p.N;
        D *= p.D;
        check();
        return *this;
    }
    Rational &operator/=(const Rational &p) {
        N *= p.D;
        D *= p.N;
        if (D < 0) N = -N, D = -D;
        check();
        return *this;
    }
    Rational operator-() const { return Rational(-N, D); }
    Rational operator+(const Rational &p) const { return Rational(*this) += p; }
    Rational operator-(const Rational &p) const { return Rational(*this) -= p; }
    Rational operator*(const Rational &p) const { return Rational(*this) *= p; }
    Rational operator/(const Rational &p) const { return Rational(*this) /= p; }
    bool operator==(const Rational &p) const { return __int128_t(N) * p.D == __int128_t(D) * p.N; }
    bool operator<(const Rational &p) const { return __int128_t(N) * p.D < __int128_t(D) * p.N; }
    bool operator<=(const Rational &p) const { return __int128_t(N) * p.D <= __int128_t(D) * p.N; }
    __int128_t numerator() { return N; }
    __int128_t denominator() { return D; }
    void check() {
        if (D < 0) {
            D = -D;
            N = -N;
        }
    }
    void divgcd() {
        auto g = gcd128(N, D);
        N /= g, D /= g;
    }
};
/*
#include "boost/rational.hpp"
using Rational = boost::rational<ll>;
*/
namespace Geometry {

constexpr double eps = 1e-10;
template <class T>
constexpr int sign(const T &a) {
    if (isZero(a)) return 0;
    if (a > 0) return 1;
    return -1;
}
template <class T, class U>
constexpr bool equal(const T &a, const U &b) {
    return isZero(a - b);
}
template <class T>
constexpr bool isZero(const T &a) {
    if constexpr (is_floating_point<T>()) return fabs(a) < eps;
    return a == 0;
}
template <class T>
constexpr T square(const T &a) {
    return a * a;
}
template <class T>
struct Vec2 {
    T x, y;
    Vec2() = default;
    Vec2(T x, T y) : x(x), y(y) {};
    constexpr Vec2 &operator+=(const Vec2 &P) {
        x += P.x, y += P.y;
        return *this;
    }
    constexpr Vec2 &operator-=(const Vec2 &P) {
        x -= P.x, y -= P.y;
        return *this;
    }
    constexpr Vec2 &operator*=(const T k) {
        x *= k, y *= k;
        return *this;
    }
    constexpr Vec2 &operator/=(const T k) {
        x /= k, y /= k;
        return *this;
    }
    constexpr Vec2 operator+() const { return *this; }
    constexpr Vec2 operator-() const { return {-x, -y}; }
    constexpr Vec2 operator+(const Vec2 &P) const { return {x + P.x, y + P.y}; }
    constexpr Vec2 operator-(const Vec2 &P) const { return {x - P.x, y - P.y}; }
    constexpr Vec2 operator*(const T k) const { return {x * k, y * k}; }
    constexpr Vec2 operator/(const T k) const { return {x / k, y / k}; }
    constexpr bool operator==(const Vec2 &P) const { return isZero(x - P.x) && isZero(y - P.y); }
    constexpr bool operator!=(const Vec2 &P) const { return !(*this == P); }
    constexpr bool operator<(const Vec2 &P) const {
        if (!isZero(x - P.x)) return x < P.x;
        return y < P.y;
    }
    constexpr bool operator>(const Vec2 &P) const { return P < *this; }
    constexpr bool isZeroVec() const { return x == T(0) && y == T(0); }
    constexpr T abs2() const { return x * x + y * y; }
    constexpr T abs() const { return sqrt(abs2()); }
    constexpr T dot(const Vec2 &v) const { return x * v.x + y * v.y; }
    constexpr T cross(const Vec2 &v) const { return x * v.y - y * v.x; }
    constexpr T dist(const Vec2 &P) const { return (P - (*this)).abs(); }
    constexpr T distSq(const Vec2 &P) const { return (P - (*this)).abs2(); }
    constexpr T unitVec() const { return (*this) / abs(); }
    Vec2 &unitize() { return *this /= abs(); }
    friend constexpr T abs2(const Vec2 &P) { return P.abs2(); }
    friend constexpr T abs(const Vec2 &P) { return P.abs(); }
    friend constexpr T dot(const Vec2 &P, const Vec2 &Q) { return P.dot(Q); }
    friend constexpr T dot(const Vec2 &A, const Vec2 &B, const Vec2 &C) { return (B - A).dot(C - A); }
    friend constexpr T cross(const Vec2 &P, const Vec2 &Q) { return P.cross(Q); }
    friend constexpr T cross(const Vec2 &A, const Vec2 &B, const Vec2 &C) { return (B - A).cross(C - A); }
    friend constexpr T dist(const Vec2 &P, const Vec2 &Q) { return P.dist(Q); }
    friend constexpr T distSq(const Vec2 &P, const Vec2 &Q) { return P.distSq(Q); }
};
template <class T>
constexpr int ccw(const Vec2<T> &A, const Vec2<T> &B, const Vec2<T> &C) {
    if (cross(B - A, C - A) > eps) return +1;
    if (cross(B - A, C - A) < -eps) return -1;
    if (dot(B - A, C - A) < -eps) return +2;
    if (abs2(B - A) + eps < abs2(C - A)) return -2;
    return 0;
}
struct Line {
    using T = Rational;
    using Point = Vec2<T>;
    Point A, B;
    Line() = default;
    Line(Point A, Point B) : A(A), B(B) {}
    const Point vec() const { return B - A; }
    const bool isParallelTo(const Line &L) const { return isZero(cross(vec(), L.vec())); }
    const bool isOrthogonalTo(const Line &L) const { return isZero(dot(vec(), L.vec())); }
    // const T distanceFrom(const Point &P) const { return abs(cross(P - A, vec())) / vec().abs(); }
    const T distanceSqFrom(const Point &P) const { return square(cross(P - A, vec())) / vec().abs2(); }
    const Point crosspoint(const Line &L) const { return A + vec() * (cross(A - L.A, L.vec())) / cross(L.vec(), vec()); }
    friend const Point crosspoint(const Line &L, const Line &M) { return L.crosspoint(M); }
};
/*
struct Segment : Line {
    Segment() = default;
    Segment(Point A, Point B) : Line(A, B) {}
    const bool intersect(const Segment &L) const { return ccw(L.A, L.B, A) * ccw(L.A, L.B, B) <= 0 && ccw(A, B, L.A) * ccw(A, B, L.B) <= 0; }
    constexpr T distanceFrom(const Point &P) const {
        if (dot(P - A, vec()) < 0) return P.dist(A);
        if (dot(P - B, vec()) > 0) return P.dist(B);
        return Line::distanceFrom(P);
    }
    constexpr T distanceFrom(const Segment &L) const {
        if (intersect(L)) return 0;
        return min({Segment::distanceFrom(L.A), Segment::distanceFrom(L.B), Segment(L).distanceFrom(A), Segment(L).distanceFrom(B)});
    }
};
*/
struct intLine {
    using T = long long;
    using Point = Vec2<T>;
    Point A, B;
    intLine() = default;
    intLine(Point A, Point B) : A(A), B(B) {}
    constexpr Point vec() const { return B - A; }
    constexpr bool isParallelTo(const intLine &L) const { return isZero(cross(vec(), L.vec())); }
    constexpr bool isOrthogonalTo(const intLine &L) const { return isZero(dot(vec(), L.vec())); }
    constexpr T distanceSqFrom(const Point &P) const { return square(cross(P - A, vec())) / vec().abs2(); }
    // constexpr Point crosspoint(const intLine &L) const { return A + vec() * (cross(A - L.A, L.vec())) / cross(L.vec(), vec()); }
};
struct intSegment : intLine {
    intSegment() = default;
    intSegment(Point A, Point B) : intLine(A, B) {}
    constexpr bool intersect(const intSegment &L) const { return ccw(L.A, L.B, A) * ccw(L.A, L.B, B) <= 0 && ccw(A, B, L.A) * ccw(A, B, L.B) <= 0; }
    constexpr T distanceSqFrom(const Point &P) {
        if (dot(P - A, vec()) < 0) return P.distSq(A);
        if (dot(P - B, vec()) > 0) return P.distSq(B);
        return intLine::distanceSqFrom(P);
    }
    constexpr T distanceSqFrom(const intSegment &L) {
        if (intersect(L)) return 0;
        return min(
            {intSegment::distanceSqFrom(L.A), intSegment::distanceSqFrom(L.B), intSegment(L).distanceSqFrom(A), intSegment(L).distanceSqFrom(B)});
    }
    friend constexpr bool intersect(const intSegment &L, const intSegment &M) { return L.intersect(M); }
};
template <class T>
vector<T> convex_hull(vector<T> ps) {
    sort(ps.begin(), ps.end());
    ps.erase(unique(ps.begin(), ps.end()), ps.end());
    int n = ps.size();
    if (n <= 2) return ps;
    vector<T> qs;
    for (auto &p : ps) {
        //<=0 if want to remove "3 points on a same line"
        while (qs.size() > 1 && cross(qs[qs.size() - 2], qs[qs.size() - 1], p) <= 0) {
            qs.pop_back();
        }
        qs.push_back(p);
    }
    int t = qs.size();
    for (int i = n - 2; i >= 0; i--) {
        T &p = ps[i];
        while ((int)qs.size() > t && cross(qs[qs.size() - 2], qs[qs.size() - 1], p) <= 0) {
            qs.pop_back();
        }
        if (i) qs.push_back(p);
    }
    return qs;
}
/*
template <typename T>
inline istream &operator>>(istream &is, Vec2<T> &rhs) {
    return is >> rhs.x >> rhs.y;
}
template <typename T>
inline ostream &operator<<(ostream &os, Vec2<T> &rhs) {
    return os << rhs.x << " " << rhs.y;
}
inline istream &operator>>(istream &is, Line &rhs) { return is >> rhs.A >> rhs.B; }
inline ostream &operator<<(ostream &os, Line &rhs) { return os << rhs.A << rhs.B; }
inline istream &operator>>(istream &is, Segment &rhs) { return is >> rhs.A >> rhs.B; }
inline ostream &operator<<(ostream &os, Segment &rhs) { return os << rhs.A << rhs.B; }
inline istream &operator>>(istream &is, intLine &rhs) { return is >> rhs.A >> rhs.B; }
inline ostream &operator<<(ostream &os, intLine &rhs) { return os << rhs.A << rhs.B; }
inline istream &operator>>(istream &is, intSegment &rhs) { return is >> rhs.A >> rhs.B; }
inline ostream &operator<<(ostream &os, intSegment &rhs) { return os << rhs.A << rhs.B; }
*/
};  // namespace Geometry
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}
struct HLD {
    vector<vector<int>> g;
    vector<int> sz, in, out, par, head, dep, ord;
    HLD(vector<vector<int>> &g_, int root = 0)
        : g(g_), sz((int)g_.size()), in((int)g_.size()), out((int)g_.size()), par((int)g_.size()), head((int)g_.size(), root), dep((int)g_.size()) {
        dfs_sz(root, -1);
        dfs_hld(root, -1);
    }
    void dfs_sz(int v, int p) {
        par[v] = p;
        sz[v] = 1;
        if (g[v].size() && g[v][0] == p) swap(g[v][0], g[v].back());
        for (auto &i : g[v]) {
            if (i != p) {
                dep[i] = dep[v] + 1;
                dfs_sz(i, v);
                sz[v] += sz[i];
                if (sz[g[v][0]] < sz[i]) swap(g[v][0], i);
            }
        }
    }
    void dfs_hld(int v, int p) {
        in[v] = ord.size();
        ord.push_back(v);
        for (auto i : g[v]) {
            if (i != p) {
                if (i == g[v][0]) {
                    // Heavy
                    head[i] = head[v];
                } else {
                    // Light
                    head[i] = i;
                }
                dfs_hld(i, v);
            }
        }
        out[v] = ord.size();
    }
    int lca(int u, int v) {
        while (1) {
            if (in[u] > in[v]) swap(u, v);
            if (head[u] == head[v]) return u;
            v = par[head[v]];
        }
    }
    int dist(int u, int v) { return dep[u] + dep[v] - 2 * dep[lca(u, v)]; }
    int la(int v, int d) {
        while (v != -1) {
            int u = head[v];
            if (in[v] - d >= in[u]) return ord[in[v] - d];
            d -= in[v] - in[u] + 1, v = par[u];
        }
        return -1;
    }
    int jump(int from, int to, int d) {
        int l = lca(from, to);
        if (d <= dep[from] - dep[l]) return la(from, d);
        d -= dep[from] - dep[l];
        if (d <= dep[to] - dep[l]) return la(to, dep[to] - dep[l] - d);
        return -1;
    }
};
template <typename T, typename U>
inline istream &operator>>(istream &is, pair<T, U> &rhs) {
    return is >> rhs.first >> rhs.second;
}
template <typename T>
inline istream &operator>>(istream &is, vector<T> &v) {
    for (auto &e : v) is >> e;
    return is;
}
template <typename T, typename U>
inline ostream &operator<<(ostream &os, const pair<T, U> &rhs) {
    return os << rhs.first << " " << rhs.second;
}
template <typename T>
inline ostream &operator<<(ostream &os, const vector<T> &v) {
    for (auto itr = v.begin(), end_itr = v.end(); itr != end_itr;) {
        os << *itr;
        if (++itr != end_itr) os << " ";
    }
    return os;
}

struct FunctionMo {
    int n;
    vector<pair<int, int>> xy;

    explicit FunctionMo(int n) : n(n) {}

    void add(int x, int y) { xy.emplace_back(x, y); }

    template <typename AX, typename SX, typename AY, typename SY, typename O>
    void build(const AX &add_x, const SX &sub_x, const AY &add_y, const SY &sub_y, const O &out) {
        int q = (int)xy.size();
        int bs = max<int>(1, sqrt(n));
        vector<int> ord(q);
        iota(begin(ord), end(ord), 0);
        sort(begin(ord), end(ord), [&](int a, int b) {
            int ablock = xy[a].first / bs, bblock = xy[b].first / bs;
            if (ablock != bblock) return ablock < bblock;
            return (ablock & 1) ? xy[a].second > xy[b].second : xy[a].second < xy[b].second;
        });
        int x = 0, y = 0;
        for (auto idx : ord) {
            while (x > xy[idx].first) add_x(x++, y);
            while (y < xy[idx].second) add_y(x, y++);
            while (x < xy[idx].first) sub_x(x--, y);
            while (y > xy[idx].second) sub_y(x, y--);
            out(idx);
        }
    }

    template <typename A, typename E, typename O>
    void build(const A &add, const E &erase, const O &out) {
        build(add, add, erase, erase, out);
    }
};
struct UnionFind {
    vector<int> par, siz;
    UnionFind(int x) {
        par.resize(x);
        siz.resize(x);
        for (int i = 0; i < x; i++) {
            par[i] = i;
            siz[i] = 1;
        }
    }
    int find(int x) {
        if (par[x] == x) return x;
        return par[x] = find(par[x]);
    }
    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y) return false;
        if (siz[x] < siz[y]) swap(x, y);
        par[y] = x;
        siz[x] += siz[y];

        return true;
    }
    bool same(int x, int y) { return find(x) == find(y); }
    int size(int x) { return siz[find(x)]; }
};
template <class T>
struct BIT {
    // 1-indexed
    int n, beki = 1;
    vector<T> bit;
    BIT(int x) {
        bit.resize(x + 1, 0);
        n = x;
        while (beki * 2 <= n) beki *= 2;
    }
    T sum(int i) {
        T res = 0;
        while (i > 0) {
            res += bit[i];
            i -= i & -i;
        }
        return res;
    }
    T sum(int l, int r) {
        //[l,r]
        return sum(r) - (l == 0 ? 0 : sum(l - 1));
    }
    void add(int i, T x) {
        while (i <= n) {
            bit[i] += x;
            i += i & -i;
        }
    }
    int lowerbound(T w) {
        if (w <= 0) return 0;
        int x = 0;
        for (int k = beki; k > 0; k >>= 1) {
            if (x + k <= n && bit[x + k] < w) {
                w -= bit[x + k];
                x += k;
            }
        }
        return x + 1;
    }
};

using mint = modint<1000000007>;
struct Line {
    ll A, B;
};
mint RtoM(Rational a) { return mint(a.numerator()) / a.denominator(); }
Rational getY_R(Line l, Rational X) {
    auto [A, B] = l;
    if (Rational(1) < X * B) return 0;
    return (Rational(1) / A * (Rational(1) - X * B));
}
mint getY(Line l, Rational X) {
    auto [A, B] = l;
    if (Rational(1) < X * B) return 0;
    return (mint(1) / A * RtoM(Rational(1) - X * B));
}
struct Point {
    Rational x, y;
};
bool isParallel(Line l, Line m) {
    auto [A, B] = l;
    auto [C, D] = m;
    return A * D == B * C;
}
Rational crosspointx(Line l, Line m) {
    auto [A, B] = l;
    auto [C, D] = m;
    auto res = Rational(A - C, A * D - B * C);
    res.check();
    return res;
}
void solve() {
    int n;
    cin >> n;
    if (n == 0) exit(0);
    vector es(n, vector<Line>(2));
    vector<Line> ES;
    rep(i, n) {
        ll x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        Line l1{y1, x1};
        Line l2{y2, x2};
        es[i] = {l1, l2};
        ES.push_back(l1);
        ES.push_back(l2);
    }
    vector<Rational> xs{0, 1};
    rep(i, ES.size()) {
        xs.push_back(Rational(1, ES[i].B));
        rep(j, i) {
            if (isParallel(ES[i], ES[j])) continue;
            xs.push_back(crosspointx(ES[i], ES[j]));
            if (xs.back() < Rational(0))
                xs.pop_back();
            else if (Rational(1) < xs.back())
                xs.pop_back();
        }
    }
    compress(xs);
    vector<mint> ans(n + 1);
    rep(xid, xs.size() - 1) {
        // cout << (ll)xs[xid].numerator() << "/" << (ll)xs[xid].denominator() << endl;
        Rational dx = xs[xid + 1] - xs[xid];
        auto mint_dx = mint(dx.numerator()) / dx.denominator();
        vector<pair<Line, int>> segs;
        rep(i, n) {
            segs.push_back({es[i][0], i});
            segs.push_back({es[i][1], i});
        }
        sort(all(segs), [&](auto L, auto M) {
            if (isParallel(L.first, M.first)) {
                return M.first.A < L.first.A;
            }
            if (L.first.A == M.first.A) return M.first.B < L.first.B;
            Rational cx = crosspointx(L.first, M.first);
            //  cx.divgcd();
            // cout << (ll)cx.numerator() << "/" << (ll)cx.denominator() << endl;
            if (Rational(0) <= cx && cx <= xs[xid]) {
                // 上にいたやつが先
                return L.first.A < M.first.A;

            } else {
                return M.first.A < L.first.A;
            }
        });
        int cnt = 0;
        mint lyl = 0, lyr = 0;
        vector<bool> appear(n);
        for (auto [seg, i] : segs) {
            mint yl = getY(seg, xs[xid]);
            mint yr = getY(seg, xs[xid + 1]);
            // cout << yl << " " << yr << endl;
            //  cout << area.numerator() << "/" << area.denominator() << " " << cnt << endl;
            ans[cnt] += (yl + yr - lyl - lyr) * mint_dx * mint::half();
            lyl = yl, lyr = yr;
            if (!appear[i]) {
                appear[i] = true;
                cnt++;
            } else
                cnt--;
        }
    }
    ans[0] = mint(1) - reduce(ans.begin() + 1, ans.end());
    cout << ans << endl;
}
/*
x=0/10000
x=1000/17000
x=2000/18000
x=8820/67620
x=8/56
x=5880/38220
x=1/5
x=160/720
x=504/2100
x=320/1280
x=240/880
x=1/3
x=1/2*/
int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int t = 1;
    // cin >> t;
    while (t) solve();
}
accuracy: 1
time_ms: 900
memory_kb: 3960
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using uint = unsigned int;
#define rep(i, n) for (int i = 0; i < n; i++)
#define all(v) v.begin(), v.end()
template <class T, class U>
inline bool chmax(T &a, U b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
template <class T, class U>
inline bool chmin(T &a, U b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template <class T>
inline void compress(vector<T> &a) {
    sort(a.begin(), a.end());
    a.erase(unique(a.begin(), a.end()), a.end());
}
template <class T>
T rand(T l, T r) {
    static mt19937 mt(random_device{}());
    // [l, r)
    if constexpr (is_integral_v<T>) {
        return uniform_int_distribution<T>(l, r - 1)(mt);
    } else if constexpr (is_floating_point_v<T>) {
        return uniform_real_distribution<T>(l, r)(mt);
    }
}
constexpr int INF = 1001001001;
constexpr ll llINF = 3000000000000000010;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using pbds_set = tree<ll, null_type, less<ll>, rb_tree_tag, tree_order_statistics_node_update>;
using pbds_mset = tree<ll, null_type, less_equal<ll>, rb_tree_tag, tree_order_statistics_node_update>;
using pbds_umap = gp_hash_table<int, int>;
using pbds_trie = trie<string, null_type, trie_string_access_traits<>, pat_trie_tag, trie_prefix_search_node_update>;
struct linear_sieve {
    vector<int> least_factor, prime_list;
    linear_sieve(int n) : least_factor(n + 1, 0) {
        for (int i = 2; i <= n; i++) {
            if (least_factor[i] == 0) {
                least_factor[i] = i;
                prime_list.push_back(i);
            }
            for (int p : prime_list) {
                if (ll(i) * p > n || p > least_factor[i]) break;
                least_factor[i * p] = p;
            }
        }
    }
};
template <int modulo>
struct modint {
    int x;
    modint() : x(0) {}
    modint(int64_t y) : x(y >= 0 ? y % modulo : (modulo - (-y) % modulo) % modulo) {}
    modint &operator+=(const modint &p) {
        if ((x += p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator-=(const modint &p) {
        if ((x += modulo - p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator*=(const modint &p) {
        x = (int)(1LL * x * p.x % modulo);
        return *this;
    }
    modint &operator/=(const modint &p) {
        *this *= p.inv();
        return *this;
    }
    modint operator-() const { return modint(-x); }
    modint operator+(const modint &p) const { return modint(*this) += p; }
    modint operator-(const modint &p) const { return modint(*this) -= p; }
    modint operator*(const modint &p) const { return modint(*this) *= p; }
    modint operator/(const modint &p) const { return modint(*this) /= p; }
    bool operator==(const modint &p) const { return x == p.x; }
    bool operator!=(const modint &p) const { return x != p.x; }
    modint inv() const {
        int a = x, b = modulo, u = 1, v = 0, t;
        while (b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return modint(u);
    }
    modint pow(int64_t n) const {
        modint ret(1), mul(x);
        while (n > 0) {
            if (n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }
    friend ostream &operator<<(ostream &os, const modint &p) { return os << p.x; }
    friend istream &operator>>(istream &is, modint &a) {
        int64_t t;
        is >> t;
        a = modint<modulo>(t);
        return (is);
    }
    int val() const { return x; }
    static constexpr int mod() { return modulo; }
    static constexpr int half() { return (modulo + 1) >> 1; }
};
ll extgcd(ll a, ll b, ll &x, ll &y) {
    // ax+by=gcd(|a|,|b|)
    if (a < 0 || b < 0) {
        ll d = extgcd(abs(a), abs(b), x, y);
        if (a < 0) x = -x;
        if (b < 0) y = -y;
        return d;
    }
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    ll d = extgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
template <typename T>
struct Binomial {
    vector<T> inv, fact, factinv;
    Binomial(int n) {
        inv.resize(n + 1);
        fact.resize(n + 1);
        factinv.resize(n + 1);
        inv[0] = fact[0] = factinv[0] = 1;
        for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i;
        factinv[n] = fact[n].inv();
        inv[n] = fact[n - 1] * factinv[n];
        for (int i = n - 1; i >= 1; i--) {
            factinv[i] = factinv[i + 1] * (i + 1);
            inv[i] = fact[i - 1] * factinv[i];
        }
    }
    T C(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r] * factinv[r];
    }
    T P(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r];
    }
    T H(int n, int r) {
        if (n == 0 && r == 0) return 1;
        if (n < 0 || r < 0) return 0;
        return r == 0 ? 1 : C(n + r - 1, r);
    }
};

struct Rational {
    ll N, D;
    Rational() = default;
    Rational(ll x) : N(x), D(1) {}
    Rational(ll n, ll d) : N(n), D(d) {}
    Rational &operator+=(const Rational &p) {
        tie(N, D) = make_pair(N * p.D + p.N * D, D * p.D);
        divgcd();
        return *this;
    }
    Rational &operator-=(const Rational &p) {
        tie(N, D) = make_pair(N * p.D - p.N * D, D * p.D);
        divgcd();
        return *this;
    }
    Rational &operator*=(const Rational &p) {
        N *= p.N;
        D *= p.D;
        divgcd();
        return *this;
    }
    Rational &operator/=(const Rational &p) {
        N *= p.D;
        D *= p.N;
        if (D < 0) N = -N, D = -D;
        divgcd();
        return *this;
    }
    Rational operator-() const { return Rational(-N, D); }
    Rational operator+(const Rational &p) const { return Rational(*this) += p; }
    Rational operator-(const Rational &p) const { return Rational(*this) -= p; }
    Rational operator*(const Rational &p) const { return Rational(*this) *= p; }
    Rational operator/(const Rational &p) const { return Rational(*this) /= p; }
    bool operator==(const Rational &p) const { return __int128_t(N) * p.D == __int128_t(D) * p.N; }
    bool operator<(const Rational &p) const { return __int128_t(N) * p.D < __int128_t(D) * p.N; }
    bool operator<=(const Rational &p) const { return __int128_t(N) * p.D <= __int128_t(D) * p.N; }
    ll numerator() { return N; }
    ll denominator() { return D; }
    void divgcd() {
        ll g = gcd(N, D);
        N /= g;
        D /= g;
        if(D<0){
            D=-D;
            N=-N;
        }
    }
};
/*
#include "boost/rational.hpp"
using Rational = boost::rational<ll>;
*/
namespace Geometry {

constexpr double eps = 1e-10;
template <class T>
constexpr int sign(const T &a) {
    if (isZero(a)) return 0;
    if (a > 0) return 1;
    return -1;
}
template <class T, class U>
constexpr bool equal(const T &a, const U &b) {
    return isZero(a - b);
}
template <class T>
constexpr bool isZero(const T &a) {
    if constexpr (is_floating_point<T>()) return fabs(a) < eps;
    return a == 0;
}
template <class T>
constexpr T square(const T &a) {
    return a * a;
}
template <class T>
struct Vec2 {
    T x, y;
    Vec2() = default;
    Vec2(T x, T y) : x(x), y(y) {};
    constexpr Vec2 &operator+=(const Vec2 &P) {
        x += P.x, y += P.y;
        return *this;
    }
    constexpr Vec2 &operator-=(const Vec2 &P) {
        x -= P.x, y -= P.y;
        return *this;
    }
    constexpr Vec2 &operator*=(const T k) {
        x *= k, y *= k;
        return *this;
    }
    constexpr Vec2 &operator/=(const T k) {
        x /= k, y /= k;
        return *this;
    }
    constexpr Vec2 operator+() const { return *this; }
    constexpr Vec2 operator-() const { return {-x, -y}; }
    constexpr Vec2 operator+(const Vec2 &P) const { return {x + P.x, y + P.y}; }
    constexpr Vec2 operator-(const Vec2 &P) const { return {x - P.x, y - P.y}; }
    constexpr Vec2 operator*(const T k) const { return {x * k, y * k}; }
    constexpr Vec2 operator/(const T k) const { return {x / k, y / k}; }
    constexpr bool operator==(const Vec2 &P) const { return isZero(x - P.x) && isZero(y - P.y); }
    constexpr bool operator!=(const Vec2 &P) const { return !(*this == P); }
    constexpr bool operator<(const Vec2 &P) const {
        if (!isZero(x - P.x)) return x < P.x;
        return y < P.y;
    }
    constexpr bool operator>(const Vec2 &P) const { return P < *this; }
    constexpr bool isZeroVec() const { return x == T(0) && y == T(0); }
    constexpr T abs2() const { return x * x + y * y; }
    constexpr T abs() const { return sqrt(abs2()); }
    constexpr T dot(const Vec2 &v) const { return x * v.x + y * v.y; }
    constexpr T cross(const Vec2 &v) const { return x * v.y - y * v.x; }
    constexpr T dist(const Vec2 &P) const { return (P - (*this)).abs(); }
    constexpr T distSq(const Vec2 &P) const { return (P - (*this)).abs2(); }
    constexpr T unitVec() const { return (*this) / abs(); }
    Vec2 &unitize() { return *this /= abs(); }
    friend constexpr T abs2(const Vec2 &P) { return P.abs2(); }
    friend constexpr T abs(const Vec2 &P) { return P.abs(); }
    friend constexpr T dot(const Vec2 &P, const Vec2 &Q) { return P.dot(Q); }
    friend constexpr T dot(const Vec2 &A, const Vec2 &B, const Vec2 &C) { return (B - A).dot(C - A); }
    friend constexpr T cross(const Vec2 &P, const Vec2 &Q) { return P.cross(Q); }
    friend constexpr T cross(const Vec2 &A, const Vec2 &B, const Vec2 &C) { return (B - A).cross(C - A); }
    friend constexpr T dist(const Vec2 &P, const Vec2 &Q) { return P.dist(Q); }
    friend constexpr T distSq(const Vec2 &P, const Vec2 &Q) { return P.distSq(Q); }
};
template <class T>
constexpr int ccw(const Vec2<T> &A, const Vec2<T> &B, const Vec2<T> &C) {
    if (cross(B - A, C - A) > eps) return +1;
    if (cross(B - A, C - A) < -eps) return -1;
    if (dot(B - A, C - A) < -eps) return +2;
    if (abs2(B - A) + eps < abs2(C - A)) return -2;
    return 0;
}
struct Line {
    using T = Rational;
    using Point = Vec2<T>;
    Point A, B;
    Line() = default;
    Line(Point A, Point B) : A(A), B(B) {}
    const Point vec() const { return B - A; }
    const bool isParallelTo(const Line &L) const { return isZero(cross(vec(), L.vec())); }
    const bool isOrthogonalTo(const Line &L) const { return isZero(dot(vec(), L.vec())); }
    // const T distanceFrom(const Point &P) const { return abs(cross(P - A, vec())) / vec().abs(); }
    const T distanceSqFrom(const Point &P) const { return square(cross(P - A, vec())) / vec().abs2(); }
    const Point crosspoint(const Line &L) const { return A + vec() * (cross(A - L.A, L.vec())) / cross(L.vec(), vec()); }
    friend const Point crosspoint(const Line &L, const Line &M) { return L.crosspoint(M); }
};
/*
struct Segment : Line {
    Segment() = default;
    Segment(Point A, Point B) : Line(A, B) {}
    const bool intersect(const Segment &L) const { return ccw(L.A, L.B, A) * ccw(L.A, L.B, B) <= 0 && ccw(A, B, L.A) * ccw(A, B, L.B) <= 0; }
    constexpr T distanceFrom(const Point &P) const {
        if (dot(P - A, vec()) < 0) return P.dist(A);
        if (dot(P - B, vec()) > 0) return P.dist(B);
        return Line::distanceFrom(P);
    }
    constexpr T distanceFrom(const Segment &L) const {
        if (intersect(L)) return 0;
        return min({Segment::distanceFrom(L.A), Segment::distanceFrom(L.B), Segment(L).distanceFrom(A), Segment(L).distanceFrom(B)});
    }
};
*/
struct intLine {
    using T = long long;
    using Point = Vec2<T>;
    Point A, B;
    intLine() = default;
    intLine(Point A, Point B) : A(A), B(B) {}
    constexpr Point vec() const { return B - A; }
    constexpr bool isParallelTo(const intLine &L) const { return isZero(cross(vec(), L.vec())); }
    constexpr bool isOrthogonalTo(const intLine &L) const { return isZero(dot(vec(), L.vec())); }
    constexpr T distanceSqFrom(const Point &P) const { return square(cross(P - A, vec())) / vec().abs2(); }
    // constexpr Point crosspoint(const intLine &L) const { return A + vec() * (cross(A - L.A, L.vec())) / cross(L.vec(), vec()); }
};
struct intSegment : intLine {
    intSegment() = default;
    intSegment(Point A, Point B) : intLine(A, B) {}
    constexpr bool intersect(const intSegment &L) const { return ccw(L.A, L.B, A) * ccw(L.A, L.B, B) <= 0 && ccw(A, B, L.A) * ccw(A, B, L.B) <= 0; }
    constexpr T distanceSqFrom(const Point &P) {
        if (dot(P - A, vec()) < 0) return P.distSq(A);
        if (dot(P - B, vec()) > 0) return P.distSq(B);
        return intLine::distanceSqFrom(P);
    }
    constexpr T distanceSqFrom(const intSegment &L) {
        if (intersect(L)) return 0;
        return min(
            {intSegment::distanceSqFrom(L.A), intSegment::distanceSqFrom(L.B), intSegment(L).distanceSqFrom(A), intSegment(L).distanceSqFrom(B)});
    }
    friend constexpr bool intersect(const intSegment &L, const intSegment &M) { return L.intersect(M); }
};
template <class T>
vector<T> convex_hull(vector<T> ps) {
    sort(ps.begin(), ps.end());
    ps.erase(unique(ps.begin(), ps.end()), ps.end());
    int n = ps.size();
    if (n <= 2) return ps;
    vector<T> qs;
    for (auto &p : ps) {
        //<=0 if want to remove "3 points on a same line"
        while (qs.size() > 1 && cross(qs[qs.size() - 2], qs[qs.size() - 1], p) <= 0) {
            qs.pop_back();
        }
        qs.push_back(p);
    }
    int t = qs.size();
    for (int i = n - 2; i >= 0; i--) {
        T &p = ps[i];
        while ((int)qs.size() > t && cross(qs[qs.size() - 2], qs[qs.size() - 1], p) <= 0) {
            qs.pop_back();
        }
        if (i) qs.push_back(p);
    }
    return qs;
}
/*
template <typename T>
inline istream &operator>>(istream &is, Vec2<T> &rhs) {
    return is >> rhs.x >> rhs.y;
}
template <typename T>
inline ostream &operator<<(ostream &os, Vec2<T> &rhs) {
    return os << rhs.x << " " << rhs.y;
}
inline istream &operator>>(istream &is, Line &rhs) { return is >> rhs.A >> rhs.B; }
inline ostream &operator<<(ostream &os, Line &rhs) { return os << rhs.A << rhs.B; }
inline istream &operator>>(istream &is, Segment &rhs) { return is >> rhs.A >> rhs.B; }
inline ostream &operator<<(ostream &os, Segment &rhs) { return os << rhs.A << rhs.B; }
inline istream &operator>>(istream &is, intLine &rhs) { return is >> rhs.A >> rhs.B; }
inline ostream &operator<<(ostream &os, intLine &rhs) { return os << rhs.A << rhs.B; }
inline istream &operator>>(istream &is, intSegment &rhs) { return is >> rhs.A >> rhs.B; }
inline ostream &operator<<(ostream &os, intSegment &rhs) { return os << rhs.A << rhs.B; }
*/
};  // namespace Geometry
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}
struct HLD {
    vector<vector<int>> g;
    vector<int> sz, in, out, par, head, dep, ord;
    HLD(vector<vector<int>> &g_, int root = 0)
        : g(g_), sz((int)g_.size()), in((int)g_.size()), out((int)g_.size()), par((int)g_.size()), head((int)g_.size(), root), dep((int)g_.size()) {
        dfs_sz(root, -1);
        dfs_hld(root, -1);
    }
    void dfs_sz(int v, int p) {
        par[v] = p;
        sz[v] = 1;
        if (g[v].size() && g[v][0] == p) swap(g[v][0], g[v].back());
        for (auto &i : g[v]) {
            if (i != p) {
                dep[i] = dep[v] + 1;
                dfs_sz(i, v);
                sz[v] += sz[i];
                if (sz[g[v][0]] < sz[i]) swap(g[v][0], i);
            }
        }
    }
    void dfs_hld(int v, int p) {
        in[v] = ord.size();
        ord.push_back(v);
        for (auto i : g[v]) {
            if (i != p) {
                if (i == g[v][0]) {
                    // Heavy
                    head[i] = head[v];
                } else {
                    // Light
                    head[i] = i;
                }
                dfs_hld(i, v);
            }
        }
        out[v] = ord.size();
    }
    int lca(int u, int v) {
        while (1) {
            if (in[u] > in[v]) swap(u, v);
            if (head[u] == head[v]) return u;
            v = par[head[v]];
        }
    }
    int dist(int u, int v) { return dep[u] + dep[v] - 2 * dep[lca(u, v)]; }
    int la(int v, int d) {
        while (v != -1) {
            int u = head[v];
            if (in[v] - d >= in[u]) return ord[in[v] - d];
            d -= in[v] - in[u] + 1, v = par[u];
        }
        return -1;
    }
    int jump(int from, int to, int d) {
        int l = lca(from, to);
        if (d <= dep[from] - dep[l]) return la(from, d);
        d -= dep[from] - dep[l];
        if (d <= dep[to] - dep[l]) return la(to, dep[to] - dep[l] - d);
        return -1;
    }
};
template <typename T, typename U>
inline istream &operator>>(istream &is, pair<T, U> &rhs) {
    return is >> rhs.first >> rhs.second;
}
template <typename T>
inline istream &operator>>(istream &is, vector<T> &v) {
    for (auto &e : v) is >> e;
    return is;
}
template <typename T, typename U>
inline ostream &operator<<(ostream &os, const pair<T, U> &rhs) {
    return os << rhs.first << " " << rhs.second;
}
template <typename T>
inline ostream &operator<<(ostream &os, const vector<T> &v) {
    for (auto itr = v.begin(), end_itr = v.end(); itr != end_itr;) {
        os << *itr;
        if (++itr != end_itr) os << " ";
    }
    return os;
}

struct FunctionMo {
    int n;
    vector<pair<int, int>> xy;

    explicit FunctionMo(int n) : n(n) {}

    void add(int x, int y) { xy.emplace_back(x, y); }

    template <typename AX, typename SX, typename AY, typename SY, typename O>
    void build(const AX &add_x, const SX &sub_x, const AY &add_y, const SY &sub_y, const O &out) {
        int q = (int)xy.size();
        int bs = max<int>(1, sqrt(n));
        vector<int> ord(q);
        iota(begin(ord), end(ord), 0);
        sort(begin(ord), end(ord), [&](int a, int b) {
            int ablock = xy[a].first / bs, bblock = xy[b].first / bs;
            if (ablock != bblock) return ablock < bblock;
            return (ablock & 1) ? xy[a].second > xy[b].second : xy[a].second < xy[b].second;
        });
        int x = 0, y = 0;
        for (auto idx : ord) {
            while (x > xy[idx].first) add_x(x++, y);
            while (y < xy[idx].second) add_y(x, y++);
            while (x < xy[idx].first) sub_x(x--, y);
            while (y > xy[idx].second) sub_y(x, y--);
            out(idx);
        }
    }

    template <typename A, typename E, typename O>
    void build(const A &add, const E &erase, const O &out) {
        build(add, add, erase, erase, out);
    }
};
struct UnionFind {
    vector<int> par, siz;
    UnionFind(int x) {
        par.resize(x);
        siz.resize(x);
        for (int i = 0; i < x; i++) {
            par[i] = i;
            siz[i] = 1;
        }
    }
    int find(int x) {
        if (par[x] == x) return x;
        return par[x] = find(par[x]);
    }
    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y) return false;
        if (siz[x] < siz[y]) swap(x, y);
        par[y] = x;
        siz[x] += siz[y];

        return true;
    }
    bool same(int x, int y) { return find(x) == find(y); }
    int size(int x) { return siz[find(x)]; }
};
template <class T>
struct BIT {
    // 1-indexed
    int n, beki = 1;
    vector<T> bit;
    BIT(int x) {
        bit.resize(x + 1, 0);
        n = x;
        while (beki * 2 <= n) beki *= 2;
    }
    T sum(int i) {
        T res = 0;
        while (i > 0) {
            res += bit[i];
            i -= i & -i;
        }
        return res;
    }
    T sum(int l, int r) {
        //[l,r]
        return sum(r) - (l == 0 ? 0 : sum(l - 1));
    }
    void add(int i, T x) {
        while (i <= n) {
            bit[i] += x;
            i += i & -i;
        }
    }
    int lowerbound(T w) {
        if (w <= 0) return 0;
        int x = 0;
        for (int k = beki; k > 0; k >>= 1) {
            if (x + k <= n && bit[x + k] < w) {
                w -= bit[x + k];
                x += k;
            }
        }
        return x + 1;
    }
};

using mint = modint<1000000007>;
void solve() {
    int n;
    cin >> n;
    if (n == 0) exit(0);
    using namespace Geometry;
    vector es(n, vector<Line>(2));
    vector<Line> ES;
    rep(i, n) {
        ll x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        Line l1{{0, Rational(1, x1)}, {Rational(1, y1), 0}};
        Line l2{{0, Rational(1, x2)}, {Rational(1, y2), 0}};
        // l1とl2の間
        es[i] = {l1, l2};
        ES.push_back(l1);
        ES.push_back(l2);
    }
    ll mxd=0;
    vector<Rational> xs{0, 1};
    rep(i, ES.size()) {
        xs.push_back(ES[i].B.x);
        rep(j, i) {
            if (ES[i].isParallelTo(ES[j])) continue;
            xs.push_back(ES[i].crosspoint(ES[j]).x);
            if (xs.back() < Rational(0))
                xs.pop_back();
            else if (Rational(1) < xs.back())
                xs.pop_back();
        }
    }
    compress(xs);
    vector<mint> ans(n + 1);
    rep(xid, xs.size() - 1) {
        // cout << "x=" << xs[xid].numerator() << "/" << xs[xid].denominator() << endl;
        Rational dx = xs[xid + 1] - xs[xid];
        auto mint_dx = mint(dx.numerator()) / dx.denominator();
        vector<tuple<Rational, Rational, int>> ys;

        rep(i, n) {
            vector<tuple<Rational, Rational, int>> a(2);
            rep(j, 2) {
                a[j] = {es[i][j].crosspoint(Line{{xs[xid], 0}, {xs[xid], 1}}).y, es[i][j].crosspoint(Line{{xs[xid + 1], 0}, {xs[xid + 1], 1}}).y, 0};
                chmax(get<0>(a[j]), 0);
                chmax(get<1>(a[j]), 0);
            }
            if (a[0] > a[1]) swap(a[0], a[1]);
            get<2>(a[0]) = 1, get<2>(a[1]) = -1;
            ys.push_back(a[0]);
            ys.push_back(a[1]);
        }
        ys.push_back({1, 1, 0});
        sort(all(ys));
        int cnt = 0;
        Rational lyl = 0, lyr = 0;
        for (auto [yl, yr, sign] : ys) {
            assert(lyl <= yl && lyr <= yr);
            // Rational area = (Y - lY) / 2;
            // cout << yl.numerator() << "/" << yl.denominator() << " " << yr.numerator() << "/" << yr.denominator() << endl;
            //  cout << area.numerator() << "/" << area.denominator() << " " << cnt << endl;
            ans[cnt] += mint(yl.numerator()) / yl.denominator() * mint_dx * mint::half();
            ans[cnt] += mint(yr.numerator()) / yr.denominator() * mint_dx * mint::half();
            ans[cnt] -= mint(lyl.numerator()) / lyl.denominator() * mint_dx * mint::half();
            ans[cnt] -= mint(lyr.numerator()) / lyr.denominator() * mint_dx * mint::half();
            lyl = yl, lyr = yr;
            cnt += sign;
        }
    }
    cout << ans << endl;
}
/*
x=0/10000
x=1000/17000
x=2000/18000
x=8820/67620
x=8/56
x=5880/38220
x=1/5
x=160/720
x=504/2100
x=320/1280
x=240/880
x=1/3
x=1/2*/
int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int t = 1;
    // cin >> t;
    while (t) solve();
}
accuracy: 0.5
time_ms: 5540
memory_kb: 3712
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using uint = unsigned int;
#define rep(i, n) for (int i = 0; i < n; i++)
#define all(v) v.begin(), v.end()
template <class T, class U>
inline bool chmax(T &a, U b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
template <class T, class U>
inline bool chmin(T &a, U b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template <class T>
inline void compress(vector<T> &a) {
    sort(a.begin(), a.end());
    a.erase(unique(a.begin(), a.end()), a.end());
}
template <class T>
T rand(T l, T r) {
    static mt19937 mt(random_device{}());
    // [l, r)
    if constexpr (is_integral_v<T>) {
        return uniform_int_distribution<T>(l, r - 1)(mt);
    } else if constexpr (is_floating_point_v<T>) {
        return uniform_real_distribution<T>(l, r)(mt);
    }
}
constexpr int INF = 1001001001;
constexpr ll llINF = 3000000000000000010;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using pbds_set = tree<ll, null_type, less<ll>, rb_tree_tag, tree_order_statistics_node_update>;
using pbds_mset = tree<ll, null_type, less_equal<ll>, rb_tree_tag, tree_order_statistics_node_update>;
using pbds_umap = gp_hash_table<int, int>;
using pbds_trie = trie<string, null_type, trie_string_access_traits<>, pat_trie_tag, trie_prefix_search_node_update>;
struct linear_sieve {
    vector<int> least_factor, prime_list;
    linear_sieve(int n) : least_factor(n + 1, 0) {
        for (int i = 2; i <= n; i++) {
            if (least_factor[i] == 0) {
                least_factor[i] = i;
                prime_list.push_back(i);
            }
            for (int p : prime_list) {
                if (ll(i) * p > n || p > least_factor[i]) break;
                least_factor[i * p] = p;
            }
        }
    }
};
template <int modulo>
struct modint {
    int x;
    modint() : x(0) {}
    modint(int64_t y) : x(y >= 0 ? y % modulo : (modulo - (-y) % modulo) % modulo) {}
    modint &operator+=(const modint &p) {
        if ((x += p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator-=(const modint &p) {
        if ((x += modulo - p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator*=(const modint &p) {
        x = (int)(1LL * x * p.x % modulo);
        return *this;
    }
    modint &operator/=(const modint &p) {
        *this *= p.inv();
        return *this;
    }
    modint operator-() const { return modint(-x); }
    modint operator+(const modint &p) const { return modint(*this) += p; }
    modint operator-(const modint &p) const { return modint(*this) -= p; }
    modint operator*(const modint &p) const { return modint(*this) *= p; }
    modint operator/(const modint &p) const { return modint(*this) /= p; }
    bool operator==(const modint &p) const { return x == p.x; }
    bool operator!=(const modint &p) const { return x != p.x; }
    modint inv() const {
        int a = x, b = modulo, u = 1, v = 0, t;
        while (b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return modint(u);
    }
    modint pow(int64_t n) const {
        modint ret(1), mul(x);
        while (n > 0) {
            if (n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }
    friend ostream &operator<<(ostream &os, const modint &p) { return os << p.x; }
    friend istream &operator>>(istream &is, modint &a) {
        int64_t t;
        is >> t;
        a = modint<modulo>(t);
        return (is);
    }
    int val() const { return x; }
    static constexpr int mod() { return modulo; }
    static constexpr int half() { return (modulo + 1) >> 1; }
};
ll extgcd(ll a, ll b, ll &x, ll &y) {
    // ax+by=gcd(|a|,|b|)
    if (a < 0 || b < 0) {
        ll d = extgcd(abs(a), abs(b), x, y);
        if (a < 0) x = -x;
        if (b < 0) y = -y;
        return d;
    }
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    ll d = extgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
template <typename T>
struct Binomial {
    vector<T> inv, fact, factinv;
    Binomial(int n) {
        inv.resize(n + 1);
        fact.resize(n + 1);
        factinv.resize(n + 1);
        inv[0] = fact[0] = factinv[0] = 1;
        for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i;
        factinv[n] = fact[n].inv();
        inv[n] = fact[n - 1] * factinv[n];
        for (int i = n - 1; i >= 1; i--) {
            factinv[i] = factinv[i + 1] * (i + 1);
            inv[i] = fact[i - 1] * factinv[i];
        }
    }
    T C(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r] * factinv[r];
    }
    T P(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r];
    }
    T H(int n, int r) {
        if (n == 0 && r == 0) return 1;
        if (n < 0 || r < 0) return 0;
        return r == 0 ? 1 : C(n + r - 1, r);
    }
};

struct Rational {
    ll N, D;
    Rational() = default;
    Rational(ll x) : N(x), D(1) {}
    Rational(ll n, ll d) : N(n), D(d) {}
    Rational &operator+=(const Rational &p) {
        tie(N, D) = make_pair(N * p.D + p.N * D, D * p.D);
        divgcd();
        return *this;
    }
    Rational &operator-=(const Rational &p) {
        tie(N, D) = make_pair(N * p.D - p.N * D, D * p.D);
        divgcd();
        return *this;
    }
    Rational &operator*=(const Rational &p) {
        N *= p.N;
        D *= p.D;
        divgcd();
        return *this;
    }
    Rational &operator/=(const Rational &p) {
        N *= p.D;
        D *= p.N;
        if (D < 0) N = -N, D = -D;
        divgcd();
        return *this;
    }
    Rational operator-() const { return Rational(-N, D); }
    Rational operator+(const Rational &p) const { return Rational(*this) += p; }
    Rational operator-(const Rational &p) const { return Rational(*this) -= p; }
    Rational operator*(const Rational &p) const { return Rational(*this) *= p; }
    Rational operator/(const Rational &p) const { return Rational(*this) /= p; }
    bool operator==(const Rational &p) const { return N * p.D == D * p.N; }
    bool operator<(const Rational &p) const { return N * p.D < D * p.N; }
    ll numerator() { return N; }
    ll denominator() { return D; }
    void divgcd() {
        ll g = gcd(N, D);
        N /= g;
        D /= g;
    }
};
/*
#include "boost/rational.hpp"
using Rational = boost::rational<ll>;
*/
namespace Geometry {

constexpr double eps = 1e-10;
template <class T>
constexpr int sign(const T &a) {
    if (isZero(a)) return 0;
    if (a > 0) return 1;
    return -1;
}
template <class T, class U>
constexpr bool equal(const T &a, const U &b) {
    return isZero(a - b);
}
template <class T>
constexpr bool isZero(const T &a) {
    if constexpr (is_floating_point<T>()) return fabs(a) < eps;
    return a == 0;
}
template <class T>
constexpr T square(const T &a) {
    return a * a;
}
template <class T>
struct Vec2 {
    T x, y;
    Vec2() = default;
    Vec2(T x, T y) : x(x), y(y) {};
    constexpr Vec2 &operator+=(const Vec2 &P) {
        x += P.x, y += P.y;
        return *this;
    }
    constexpr Vec2 &operator-=(const Vec2 &P) {
        x -= P.x, y -= P.y;
        return *this;
    }
    constexpr Vec2 &operator*=(const T k) {
        x *= k, y *= k;
        return *this;
    }
    constexpr Vec2 &operator/=(const T k) {
        x /= k, y /= k;
        return *this;
    }
    constexpr Vec2 operator+() const { return *this; }
    constexpr Vec2 operator-() const { return {-x, -y}; }
    constexpr Vec2 operator+(const Vec2 &P) const { return {x + P.x, y + P.y}; }
    constexpr Vec2 operator-(const Vec2 &P) const { return {x - P.x, y - P.y}; }
    constexpr Vec2 operator*(const T k) const { return {x * k, y * k}; }
    constexpr Vec2 operator/(const T k) const { return {x / k, y / k}; }
    constexpr bool operator==(const Vec2 &P) const { return isZero(x - P.x) && isZero(y - P.y); }
    constexpr bool operator!=(const Vec2 &P) const { return !(*this == P); }
    constexpr bool operator<(const Vec2 &P) const {
        if (!isZero(x - P.x)) return x < P.x;
        return y < P.y;
    }
    constexpr bool operator>(const Vec2 &P) const { return P < *this; }
    constexpr bool isZeroVec() const { return x == T(0) && y == T(0); }
    constexpr T abs2() const { return x * x + y * y; }
    constexpr T abs() const { return sqrt(abs2()); }
    constexpr T dot(const Vec2 &v) const { return x * v.x + y * v.y; }
    constexpr T cross(const Vec2 &v) const { return x * v.y - y * v.x; }
    constexpr T dist(const Vec2 &P) const { return (P - (*this)).abs(); }
    constexpr T distSq(const Vec2 &P) const { return (P - (*this)).abs2(); }
    constexpr T unitVec() const { return (*this) / abs(); }
    Vec2 &unitize() { return *this /= abs(); }
    friend constexpr T abs2(const Vec2 &P) { return P.abs2(); }
    friend constexpr T abs(const Vec2 &P) { return P.abs(); }
    friend constexpr T dot(const Vec2 &P, const Vec2 &Q) { return P.dot(Q); }
    friend constexpr T dot(const Vec2 &A, const Vec2 &B, const Vec2 &C) { return (B - A).dot(C - A); }
    friend constexpr T cross(const Vec2 &P, const Vec2 &Q) { return P.cross(Q); }
    friend constexpr T cross(const Vec2 &A, const Vec2 &B, const Vec2 &C) { return (B - A).cross(C - A); }
    friend constexpr T dist(const Vec2 &P, const Vec2 &Q) { return P.dist(Q); }
    friend constexpr T distSq(const Vec2 &P, const Vec2 &Q) { return P.distSq(Q); }
};
template <class T>
constexpr int ccw(const Vec2<T> &A, const Vec2<T> &B, const Vec2<T> &C) {
    if (cross(B - A, C - A) > eps) return +1;
    if (cross(B - A, C - A) < -eps) return -1;
    if (dot(B - A, C - A) < -eps) return +2;
    if (abs2(B - A) + eps < abs2(C - A)) return -2;
    return 0;
}
struct Line {
    using T = Rational;
    using Point = Vec2<T>;
    Point A, B;
    Line() = default;
    Line(Point A, Point B) : A(A), B(B) {}
    const Point vec() const { return B - A; }
    const bool isParallelTo(const Line &L) const { return isZero(cross(vec(), L.vec())); }
    const bool isOrthogonalTo(const Line &L) const { return isZero(dot(vec(), L.vec())); }
    // const T distanceFrom(const Point &P) const { return abs(cross(P - A, vec())) / vec().abs(); }
    const T distanceSqFrom(const Point &P) const { return square(cross(P - A, vec())) / vec().abs2(); }
    const Point crosspoint(const Line &L) const { return A + vec() * (cross(A - L.A, L.vec())) / cross(L.vec(), vec()); }
    friend const Point crosspoint(const Line &L, const Line &M) { return L.crosspoint(M); }
};
/*
struct Segment : Line {
    Segment() = default;
    Segment(Point A, Point B) : Line(A, B) {}
    const bool intersect(const Segment &L) const { return ccw(L.A, L.B, A) * ccw(L.A, L.B, B) <= 0 && ccw(A, B, L.A) * ccw(A, B, L.B) <= 0; }
    constexpr T distanceFrom(const Point &P) const {
        if (dot(P - A, vec()) < 0) return P.dist(A);
        if (dot(P - B, vec()) > 0) return P.dist(B);
        return Line::distanceFrom(P);
    }
    constexpr T distanceFrom(const Segment &L) const {
        if (intersect(L)) return 0;
        return min({Segment::distanceFrom(L.A), Segment::distanceFrom(L.B), Segment(L).distanceFrom(A), Segment(L).distanceFrom(B)});
    }
};
*/
struct intLine {
    using T = long long;
    using Point = Vec2<T>;
    Point A, B;
    intLine() = default;
    intLine(Point A, Point B) : A(A), B(B) {}
    constexpr Point vec() const { return B - A; }
    constexpr bool isParallelTo(const intLine &L) const { return isZero(cross(vec(), L.vec())); }
    constexpr bool isOrthogonalTo(const intLine &L) const { return isZero(dot(vec(), L.vec())); }
    constexpr T distanceSqFrom(const Point &P) const { return square(cross(P - A, vec())) / vec().abs2(); }
    // constexpr Point crosspoint(const intLine &L) const { return A + vec() * (cross(A - L.A, L.vec())) / cross(L.vec(), vec()); }
};
struct intSegment : intLine {
    intSegment() = default;
    intSegment(Point A, Point B) : intLine(A, B) {}
    constexpr bool intersect(const intSegment &L) const { return ccw(L.A, L.B, A) * ccw(L.A, L.B, B) <= 0 && ccw(A, B, L.A) * ccw(A, B, L.B) <= 0; }
    constexpr T distanceSqFrom(const Point &P) {
        if (dot(P - A, vec()) < 0) return P.distSq(A);
        if (dot(P - B, vec()) > 0) return P.distSq(B);
        return intLine::distanceSqFrom(P);
    }
    constexpr T distanceSqFrom(const intSegment &L) {
        if (intersect(L)) return 0;
        return min(
            {intSegment::distanceSqFrom(L.A), intSegment::distanceSqFrom(L.B), intSegment(L).distanceSqFrom(A), intSegment(L).distanceSqFrom(B)});
    }
    friend constexpr bool intersect(const intSegment &L, const intSegment &M) { return L.intersect(M); }
};
template <class T>
vector<T> convex_hull(vector<T> ps) {
    sort(ps.begin(), ps.end());
    ps.erase(unique(ps.begin(), ps.end()), ps.end());
    int n = ps.size();
    if (n <= 2) return ps;
    vector<T> qs;
    for (auto &p : ps) {
        //<=0 if want to remove "3 points on a same line"
        while (qs.size() > 1 && cross(qs[qs.size() - 2], qs[qs.size() - 1], p) <= 0) {
            qs.pop_back();
        }
        qs.push_back(p);
    }
    int t = qs.size();
    for (int i = n - 2; i >= 0; i--) {
        T &p = ps[i];
        while ((int)qs.size() > t && cross(qs[qs.size() - 2], qs[qs.size() - 1], p) <= 0) {
            qs.pop_back();
        }
        if (i) qs.push_back(p);
    }
    return qs;
}
/*
template <typename T>
inline istream &operator>>(istream &is, Vec2<T> &rhs) {
    return is >> rhs.x >> rhs.y;
}
template <typename T>
inline ostream &operator<<(ostream &os, Vec2<T> &rhs) {
    return os << rhs.x << " " << rhs.y;
}
inline istream &operator>>(istream &is, Line &rhs) { return is >> rhs.A >> rhs.B; }
inline ostream &operator<<(ostream &os, Line &rhs) { return os << rhs.A << rhs.B; }
inline istream &operator>>(istream &is, Segment &rhs) { return is >> rhs.A >> rhs.B; }
inline ostream &operator<<(ostream &os, Segment &rhs) { return os << rhs.A << rhs.B; }
inline istream &operator>>(istream &is, intLine &rhs) { return is >> rhs.A >> rhs.B; }
inline ostream &operator<<(ostream &os, intLine &rhs) { return os << rhs.A << rhs.B; }
inline istream &operator>>(istream &is, intSegment &rhs) { return is >> rhs.A >> rhs.B; }
inline ostream &operator<<(ostream &os, intSegment &rhs) { return os << rhs.A << rhs.B; }
*/
};  // namespace Geometry
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}
struct HLD {
    vector<vector<int>> g;
    vector<int> sz, in, out, par, head, dep, ord;
    HLD(vector<vector<int>> &g_, int root = 0)
        : g(g_), sz((int)g_.size()), in((int)g_.size()), out((int)g_.size()), par((int)g_.size()), head((int)g_.size(), root), dep((int)g_.size()) {
        dfs_sz(root, -1);
        dfs_hld(root, -1);
    }
    void dfs_sz(int v, int p) {
        par[v] = p;
        sz[v] = 1;
        if (g[v].size() && g[v][0] == p) swap(g[v][0], g[v].back());
        for (auto &i : g[v]) {
            if (i != p) {
                dep[i] = dep[v] + 1;
                dfs_sz(i, v);
                sz[v] += sz[i];
                if (sz[g[v][0]] < sz[i]) swap(g[v][0], i);
            }
        }
    }
    void dfs_hld(int v, int p) {
        in[v] = ord.size();
        ord.push_back(v);
        for (auto i : g[v]) {
            if (i != p) {
                if (i == g[v][0]) {
                    // Heavy
                    head[i] = head[v];
                } else {
                    // Light
                    head[i] = i;
                }
                dfs_hld(i, v);
            }
        }
        out[v] = ord.size();
    }
    int lca(int u, int v) {
        while (1) {
            if (in[u] > in[v]) swap(u, v);
            if (head[u] == head[v]) return u;
            v = par[head[v]];
        }
    }
    int dist(int u, int v) { return dep[u] + dep[v] - 2 * dep[lca(u, v)]; }
    int la(int v, int d) {
        while (v != -1) {
            int u = head[v];
            if (in[v] - d >= in[u]) return ord[in[v] - d];
            d -= in[v] - in[u] + 1, v = par[u];
        }
        return -1;
    }
    int jump(int from, int to, int d) {
        int l = lca(from, to);
        if (d <= dep[from] - dep[l]) return la(from, d);
        d -= dep[from] - dep[l];
        if (d <= dep[to] - dep[l]) return la(to, dep[to] - dep[l] - d);
        return -1;
    }
};
template <typename T, typename U>
inline istream &operator>>(istream &is, pair<T, U> &rhs) {
    return is >> rhs.first >> rhs.second;
}
template <typename T>
inline istream &operator>>(istream &is, vector<T> &v) {
    for (auto &e : v) is >> e;
    return is;
}
template <typename T, typename U>
inline ostream &operator<<(ostream &os, const pair<T, U> &rhs) {
    return os << rhs.first << " " << rhs.second;
}
template <typename T>
inline ostream &operator<<(ostream &os, const vector<T> &v) {
    for (auto itr = v.begin(), end_itr = v.end(); itr != end_itr;) {
        os << *itr;
        if (++itr != end_itr) os << " ";
    }
    return os;
}

struct FunctionMo {
    int n;
    vector<pair<int, int>> xy;

    explicit FunctionMo(int n) : n(n) {}

    void add(int x, int y) { xy.emplace_back(x, y); }

    template <typename AX, typename SX, typename AY, typename SY, typename O>
    void build(const AX &add_x, const SX &sub_x, const AY &add_y, const SY &sub_y, const O &out) {
        int q = (int)xy.size();
        int bs = max<int>(1, sqrt(n));
        vector<int> ord(q);
        iota(begin(ord), end(ord), 0);
        sort(begin(ord), end(ord), [&](int a, int b) {
            int ablock = xy[a].first / bs, bblock = xy[b].first / bs;
            if (ablock != bblock) return ablock < bblock;
            return (ablock & 1) ? xy[a].second > xy[b].second : xy[a].second < xy[b].second;
        });
        int x = 0, y = 0;
        for (auto idx : ord) {
            while (x > xy[idx].first) add_x(x++, y);
            while (y < xy[idx].second) add_y(x, y++);
            while (x < xy[idx].first) sub_x(x--, y);
            while (y > xy[idx].second) sub_y(x, y--);
            out(idx);
        }
    }

    template <typename A, typename E, typename O>
    void build(const A &add, const E &erase, const O &out) {
        build(add, add, erase, erase, out);
    }
};
struct UnionFind {
    vector<int> par, siz;
    UnionFind(int x) {
        par.resize(x);
        siz.resize(x);
        for (int i = 0; i < x; i++) {
            par[i] = i;
            siz[i] = 1;
        }
    }
    int find(int x) {
        if (par[x] == x) return x;
        return par[x] = find(par[x]);
    }
    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y) return false;
        if (siz[x] < siz[y]) swap(x, y);
        par[y] = x;
        siz[x] += siz[y];

        return true;
    }
    bool same(int x, int y) { return find(x) == find(y); }
    int size(int x) { return siz[find(x)]; }
};
template <class T>
struct BIT {
    // 1-indexed
    int n, beki = 1;
    vector<T> bit;
    BIT(int x) {
        bit.resize(x + 1, 0);
        n = x;
        while (beki * 2 <= n) beki *= 2;
    }
    T sum(int i) {
        T res = 0;
        while (i > 0) {
            res += bit[i];
            i -= i & -i;
        }
        return res;
    }
    T sum(int l, int r) {
        //[l,r]
        return sum(r) - (l == 0 ? 0 : sum(l - 1));
    }
    void add(int i, T x) {
        while (i <= n) {
            bit[i] += x;
            i += i & -i;
        }
    }
    int lowerbound(T w) {
        if (w <= 0) return 0;
        int x = 0;
        for (int k = beki; k > 0; k >>= 1) {
            if (x + k <= n && bit[x + k] < w) {
                w -= bit[x + k];
                x += k;
            }
        }
        return x + 1;
    }
};

using mint = modint<1000000007>;
void solve() {
    int n;
    cin >> n;
    if (n == 0) exit(0);
    using namespace Geometry;
    vector es(n, vector<Line>(2));
    vector<Line> ES;
    rep(i, n) {
        ll x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        Line l1{{0, Rational(1, x1)}, {Rational(1, y1), 0}};
        Line l2{{0, Rational(1, x2)}, {Rational(1, y2), 0}};
        // l1とl2の間
        es[i] = {l1, l2};
        ES.push_back(l1);
        ES.push_back(l2);
    }
    vector<Rational> xs{0, 1};
    rep(i, ES.size()) {
        xs.push_back(ES[i].B.x);
        rep(j, i) {
            if (ES[i].isParallelTo(ES[j])) continue;
            xs.push_back(ES[i].crosspoint(ES[j]).x);
            if (xs.back() < 0) xs.pop_back();
            if (Rational(1) < xs.back()) xs.pop_back();
        }
    }
    compress(xs);
    vector<mint> ans(n + 1);
    rep(xid, xs.size() - 1) {
        // cout << "x=" << xs[xid].numerator() << "/" << xs[xid].denominator() << endl;
        Rational dx = xs[xid + 1] - xs[xid];
        auto mint_dx = mint(dx.numerator()) / dx.denominator();
        vector<tuple<Rational, Rational, int>> ys;

        rep(i, n) {
            vector<tuple<Rational, Rational, int>> a(2);
            rep(j, 2) {
                a[j] = {es[i][j].crosspoint(Line{{xs[xid], 0}, {xs[xid], 1}}).y, es[i][j].crosspoint(Line{{xs[xid + 1], 0}, {xs[xid + 1], 1}}).y, 0};
                chmax(get<0>(a[j]), 0);
                chmax(get<1>(a[j]), 0);
            }
            if (a[0] > a[1]) swap(a[0], a[1]);
            get<2>(a[0]) = 1, get<2>(a[1]) = -1;
            ys.push_back(a[0]);
            ys.push_back(a[1]);
        }
        ys.push_back({1, 1, 0});
        sort(all(ys));
        int cnt = 0;
        Rational lyl = 0, lyr = 0;

        for (auto [yl, yr, sign] : ys) {
            // assert(lyl <= yl && lyr <= yr);
            Rational area = (yl + yr - lyl - lyr) / 2;
            // cout << yl.numerator() << "/" << yl.denominator() << " " << yr.numerator() << "/" << yr.denominator() << endl;
            //  cout << area.numerator() << "/" << area.denominator() << " " << cnt << endl;
            ans[cnt] += mint(area.numerator()) / area.denominator() * mint_dx;
            lyl = yl, lyr = yr;
            cnt += sign;
        }
    }
    cout << ans << endl;
}
/*
x=0/10000
x=1000/17000
x=2000/18000
x=8820/67620
x=8/56
x=5880/38220
x=1/5
x=160/720
x=504/2100
x=320/1280
x=240/880
x=1/3
x=1/2*/
int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int t = 1;
    // cin >> t;
    while (t) solve();
}
accuracy: 0.5
time_ms: 6260
memory_kb: 3712
final_rank: 13

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef vector<ll> vi;
typedef vector<vi> vvi;
typedef vector<vvi> vvvi;
typedef vector<bool> vb;
typedef vector<vb> vvb;
typedef vector<vvb> vvvb;
typedef vector<vvvb> vvvvb;
typedef pair<ll,ll> pi;
typedef pair<ll,pi> ppi;
#define FOR(i,l,r) for(ll i=l;i<r;i++)
#define REP(i,n) FOR(i,0,n)
#define RFOR(i,l,r) for(ll i=r-1;i>=l;i--)
#define RREP(i,n) RFOR(i,0,n)
#define sz(A) (ll)(A.size())
#define ALL(A) A.begin(),A.end()
#define LB(A,x) (ll)(lower_bound(ALL(A),x)-A.begin())
#define UB(A,x) (ll)(upper_bound(ALL(A),x)-A.begin())
#define COU(A,x) (UB(A,x)-LB(A,x))
#define F first
#define S second
template<typename T>using min_priority_queue=priority_queue<T,vector<T>,greater<T>>;
template<typename T1,typename T2>ostream&operator<<(ostream&os,pair<T1,T2>&p){os<<p.F<<" "<<p.S;return os;}
template<typename T1,typename T2>istream&operator>>(istream&is,pair<T1,T2>&p){is>>p.F>>p.S;return is;}
template<typename T>ostream&operator<<(ostream&os,vector<T>&v){REP(i,sz(v))os<<v[i]<<(i+1!=sz(v)?" ":"");return os;}
template<typename T>istream&operator>>(istream&is,vector<T>&v){for(T&in:v)is>>in;return is;}
template<class T>bool chmax(T&a,T b){if(a<b){a=b;return 1;}return 0;}
template<class T>bool chmin(T&a,T b){if(b<a){a=b;return 1;}return 0;}
const ll mod=998244353;
template<const long long int mod=998244353>
struct modint{
  using mint=modint<mod>;
  long long int x;
  modint(long long int _x=0):x(_x%mod){if(x<0)x+=mod;}
  long long int val(){return x;}
  mint&operator=(const mint&a){x=a.x;return *this;}
  mint&operator+=(const mint&a){x+=a.x;if(x>=mod)x-=mod;return *this;}
  mint&operator-=(const mint&a){x-=a.x;if(x<0)x+=mod;return *this;}
  mint&operator*=(const mint&a){x*=a.x;x%=mod;return *this;}
  friend mint operator+(const mint&a,const mint&b){return mint(a)+=b;}
  friend mint operator-(const mint&a,const mint&b){return mint(a)-=b;}
  friend mint operator*(const mint&a,const mint&b){return mint(a)*=b;}
  mint operator-()const{return mint(0)-*this;}
  mint pow(long long int n){
    if(!n)return 1;
    mint a=1;
    mint _x=x;
    while(n){
      if(n&1)a*=_x;
      _x=_x*_x;n>>=1;
    }
    return a;
  }
  mint inv(){return pow(mod-2);}
  mint&operator/=(mint&a){return *this*=a.inv();}
  friend mint operator/(const mint&a,mint b){return mint(a)/=b;}
};
using mint=modint<1000000007>;
struct rat{
    ll x,y;
    rat(ll n):x(n),y(1){}
    rat(ll _x,ll _y):x(_x),y(_y){assert(y);ll g=__gcd(x,y);x/=g;y/=g;if(y<0)x*=-1,y*=-1;}
    rat operator+(rat r){return rat(x*r.y+r.x*y,y*r.y);}
    rat operator-(rat r){return rat(x*r.y-r.x*y,y*r.y);}
    rat operator*(rat r){return rat(x*r.x,y*r.y);}
    rat operator/(rat r){return rat(x*r.y,y*r.x);}
    bool operator<(rat r){return x*r.y<y*r.x;}
    bool operator==(rat r){return x==r.x&&y==r.y;}
    bool operator!=(rat r){return !(*this==r);}
    bool operator<=(rat r){return x*r.y<=y*r.x;}
    bool operator>(rat r){return x*r.y>y*r.x;}
    friend rat operator+(const rat&a,const rat&b){return rat(a.x*b.y+b.x*a.y,a.y*b.y);}
    friend rat operator-(const rat&a,const rat&b){return rat(a.x*b.y-b.x*a.y,a.y*b.y);}
    friend rat operator*(const rat&a,const rat&b){return rat(a.x*b.x,a.y*b.y);}
    friend rat operator/(const rat&a,const rat&b){return rat(a.x*b.y,a.y*b.x);}
    mint val(){return (mint)x/y;}
};
int main(){
    while(1){
        int N;cin>>N;
        if(!N)return 0;
        vector<pair<pi,pi>>A(N);
        cin>>A;
        REP(i,N)if(A[i].F<A[i].S)swap(A[i].F,A[i].S);
        vector<rat>X;
        {
            X.emplace_back(rat(0,1));
            X.emplace_back(rat(1,1));
            vector<pi>B;
            REP(i,N)B.emplace_back(A[i].F),B.emplace_back(A[i].S);
            sort(ALL(B));reverse(ALL(B));
            REP(i,sz(B))X.emplace_back(rat(1,B[i].F));
            REP(i,sz(B))REP(j,i){
                if(B[i].F==B[j].F){X.emplace_back(rat(1,B[i].F));continue;}
                if(B[i].S<=B[j].S)continue;
                //運命の交差点
                X.emplace_back(rat(B[i].S-B[j].S,B[j].F*B[i].S-B[i].F*B[j].S));
            }
            sort(ALL(X));
            X.erase(unique(ALL(X)),X.end());
        }
        vector<mint>ans(N+1);
        REP(i,sz(X)-1){
            vector<pair<rat,rat>>S;
            //弐断
            S.emplace_back(make_pair(0,0));
            S.emplace_back(make_pair(1,1));
            REP(j,N){
                if(rat(1,A[j].F.F)>X[i])S.emplace_back(make_pair((1-A[j].F.F*X[i])/A[j].F.S,(1-A[j].F.F*X[i+1])/A[j].F.S));
                if(rat(1,A[j].S.F)>X[i])S.emplace_back(make_pair((1-A[j].S.F*X[i])/A[j].S.S,(1-A[j].S.F*X[i+1])/A[j].S.S));
            }
            sort(ALL(S),[](pair<rat,rat>a,pair<rat,rat>b){return a.F<b.F||(a.F==b.F&&a.S<b.S);});
            vi T(sz(S)-1);
            REP(j,N)if(rat(1,A[j].S.F)>X[i]){
                auto seg1=S[0];
                auto seg2=make_pair((1-A[j].S.F*X[i])/A[j].S.S,(1-A[j].S.F*X[i+1])/A[j].S.S);
                if(rat(1,A[j].F.F)>X[i])seg1=make_pair((1-A[j].F.F*X[i])/A[j].F.S,(1-A[j].F.F*X[i+1])/A[j].F.S);
                ll t1=lower_bound(ALL(S),seg1,[](pair<rat,rat>a,pair<rat,rat>b){return a.F<b.F||(a.F==b.F&&a.S<b.S);})-S.begin(),t2=lower_bound(ALL(S),seg2,[](pair<rat,rat>a,pair<rat,rat>b){return a.F<b.F||(a.F==b.F&&a.S<b.S);})-S.begin();
                if(t1>t2)swap(t1,t2);
                FOR(k,t1,t2)T[k]++;
            }
            vector<mint>P(sz(S));
            REP(j,sz(S))P[j]=S[j].F.val()+S[j].S.val();
            mint d=X[i+1].val()-X[i].val();
            REP(j,sz(S)-1)ans[T[j]]+=(P[j+1]-P[j])*d;
        }
        REP(i,N+1)ans[i]=ans[i]/2;
        vi _ans(N+1);
        REP(i,N+1)_ans[i]=ans[i].val();
        cout<<_ans<<endl;
    }
    return 0;
}
accuracy: 1
time_ms: 6190
memory_kb: 3512
final_rank: 7

code_snippet: #line 2 "cp-library/src/cp-template.hpp"
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull  = unsigned long long;
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
template < class T > bool chmin(T& a, T b) { if(a > b) { a = b; return true; } return false; }
template < class T > bool chmax(T& a, T b) { if(a < b) { a = b; return true; } return false; }
template < class T, class U > T ceil (T x, U y) { return (x > 0 ? (x + y - 1) / y :           x / y); }
template < class T, class U > T floor(T x, U y) { return (x > 0 ?           x / y : (x - y + 1) / y); }
int popcnt(i32 x) { return __builtin_popcount(x); }
int popcnt(u32 x) { return __builtin_popcount(x); }
int popcnt(i64 x) { return __builtin_popcountll(x); }
int popcnt(u64 x) { return __builtin_popcountll(x); }

#line 2 "cp-library/src/utility/rep_itr.hpp"
template < class T > struct itr_rep {
    T i, d;
    constexpr itr_rep(const T i) noexcept : i(i), d(1) {}
    constexpr itr_rep(const T i, const T d) noexcept : i(i), d(d) {}
    void operator++() noexcept { i += d; }
    constexpr int operator*() const noexcept { return i; }
    constexpr bool operator!=(const itr_rep x) const noexcept { return d > 0 ? i < x.i : i > x.i; }
};

template < class T > struct rep {
    const itr_rep< T > s, t;
    constexpr rep(const T t) noexcept : s(0), t(t) {}
    constexpr rep(const T s, const T t) noexcept : s(s), t(t) {}
    constexpr rep(const T s, const T t, const T d) noexcept : s(s, d), t(t, d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};

template < class T > struct revrep {
    const itr_rep < T > s, t;
    constexpr revrep(const T t) noexcept : s(t - 1, -1), t(-1, -1) {}
    constexpr revrep(const T s, const T t) noexcept : s(t - 1, -1), t(s - 1, -1) {}
    constexpr revrep(const T s, const T t, const T d) noexcept : s(t - 1, -d), t(s - 1, -d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};
#line 3 "cp-library/src/utility/io.hpp"

/* 128bit integer */
istream& operator>>(istream& is, i128& x) {
    std::string s; is >> s;
    int pm = (s[0] == '-');
    x = 0;
    for(int i : rep(pm, int(s.size()))) x = x * 10 + (s[i] - '0');
    if(pm) x *= -1;
    return is;
}
ostream& operator<<(ostream& os, const i128& x) {
    if(x == 0) return os << '0';
    i128 y = x;
    if(y < 0) { os << '-'; y *= -1; }
    std::vector<int> ny;
    while(y > 0) { ny.push_back(y % 10); y /= 10; }
    for(int i : revrep(ny.size())) os << ny[i];
    return os;
}

template < class S, class T > istream& operator>>(istream& is,       std::pair< S, T >& x) { is >> x.first        >> x.second; return is; }
template < class S, class T > ostream& operator<<(ostream& os, const std::pair< S, T >& x) { os << x.first << " " << x.second; return os; }

namespace scanner {
    struct sca {
        template < class T > operator T() {
            T s; std::cin >> s; return s;
        }
    };
    struct vec {
        int n;
        vec(int n) : n(n) {}
        template < class T > operator std::vector< T >() {
            std::vector< T > v(n);
            for(T& x : v) std::cin >> x;
            return v;
        }
    };
    struct mat {
        int h, w;
        mat(int h, int w) : h(h), w(w) {}
        template < class T > operator std::vector< std::vector< T > >() {
            std::vector m(h, std::vector< T >(w));
            for(std::vector< T >& v : m) for(T& x : v) std::cin >> x;
            return m;
        }
    };
    struct speedup {
        speedup() {
            std::cin.tie(0);
            std::ios::sync_with_stdio(0);
        }
    } speedup_instance;
}
scanner::sca in() { return scanner::sca(); }
scanner::vec in(int n) { return scanner::vec(n); }
scanner::mat in(int h, int w) { return scanner::mat(h, w); }

namespace printer {
    void precision(int d) { std::cout << std::fixed << std::setprecision(d); }
    void flush() { std::cout.flush(); }
}

template < class T >
ostream& operator<<(ostream& os, const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) { os << a[i]; if(i != n - 1) os << ' '; }
    return os;
}

int print() { std::cout << '\n'; return 0; }
template < class head, class... tail > int print(head&& h, tail&&... t) {
    std::cout << h; if(sizeof...(tail)) std::cout << ' ';
    return print(std::forward<tail>(t)...);
}
template < class T > int print_n(const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) std::cout << a[i] << "\n";
    return 0;
}


#line 2 "cp-library/src/utility/key_val.hpp"

template < class K, class V >
struct key_val {
    K key; V val;
    key_val() {}
    key_val(K key, V val) : key(key), val(val) {}
    template < std::size_t Index >
    std::tuple_element_t< Index, key_val >& get() {
        if constexpr (Index == 0) return key;
        if constexpr (Index == 1) return val;
    }
};

namespace std {

template < class K, class V > struct tuple_size < key_val< K, V > > : integral_constant< size_t, 2 > {};
template < class K, class V > struct tuple_element < 0, key_val< K, V > > { using type = K; };
template < class K, class V > struct tuple_element < 1, key_val< K, V > > { using type = V; };

}
#line 2 "cp-library/src/utility/vec_op.hpp"
template < class T > key_val< int, T > max_of(const vector< T >& a) {
    int i = std::max_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class T > key_val< int, T > min_of(const vector< T >& a) {
    int i = std::min_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class S, class T > S sum_of(const vector< T >& a) {
    S sum = 0;
    for(const T x : a) sum += x;
    return sum;
}
template < class S, class T > vector< S > freq_of(const vector< T >& a, T L, T R) {
    vector< S > res(R - L, S(0));
    for(const T x : a) res[x - L] += 1;
    return res;
}
template < class S, class T > struct prefix_sum {
    vector< S > s;
    prefix_sum(const vector< T >& a) : s(a) {
        s.insert(s.begin(), S(0));
        for(int i : rep(a.size())) s[i + 1] += s[i];
    }
    // [L, R)
    S sum(int L, int R) { return s[R] - s[L]; }
};
#line 3 "cp-library/src/utility/heap.hpp"

template < class T > using heap_min = std::priority_queue< T, std::vector< T >, std::greater< T > >;
template < class T > using heap_max = std::priority_queue< T, std::vector< T >, std::less< T > >;

#line 27 "cp-library/src/cp-template.hpp"

#line 1 "cp-library/src/algorithm/bin_search.hpp"
template < class T, class F >
T bin_search(T ok, T ng, F f) {
    while(abs(ng - ok) > 1) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

template < class T, class F >
T bin_search_real(T ok, T ng, F f, int step = 80) {
    while(step--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
#line 2 "cp-library/src/algorithm/argsort.hpp"

template < class T > std::vector< int > argsort(const std::vector< T > &a) {
    std::vector< int > ids((int)a.size());
    std::iota(ids.begin(), ids.end(), 0);
    std::sort(ids.begin(), ids.end(), [&](int i, int j) {
        return a[i] < a[j] || (a[i] == a[j] && i < j);
    });
    return ids;
}
#line 1 "macro.hpp"
namespace macro {

using size_type = int;
template < class container > void  sort(container& a) { std::sort(std:: begin(a), std:: end(a)); }
template < class container > void rsort(container& a) { std::sort(std::rbegin(a), std::rend(a)); }
template < class container > void reverse(container& a) { std::reverse(std::begin(a), std::end(a)); }
template < class container > void unique(container& a) {
    std::sort(std::begin(a), std::end(a));
    a.erase(std::unique(std::begin(a), std::end(a)), std::end(a));
}
template < class container > container  sorted(const container& a) { container b = a;  sort(b); return std::move(b); }
template < class container > container rsorted(const container& a) { container b = a; rsort(b); return std::move(b); }
template < class container, class compare > void sort(container& a, const compare& cmp) { std::sort(std::begin(a), std::end(a), cmp); }
template < class container, class compare > container sorted(const container& a, const compare& cmp) { container b = a; sort(b, cmp); return std::move(b); }
template < class container, class value > size_type lower_bound(const container& a, const value& x) { return std::lower_bound(std::begin(a), std::end(a), x) - std::begin(a); }
template < class container, class value > size_type upper_bound(const container& a, const value& x) { return std::upper_bound(std::begin(a), std::end(a), x) - std::begin(a); }

const std::vector<std::pair<size_type, size_type>> dir4 = { {+1,  0}, {-1,  0}, { 0, +1}, { 0, -1} };
const std::vector<std::pair<size_type, size_type>> dir8 = { {-1, -1}, {-1,  0}, {-1, +1}, { 0, -1}, { 0, +1}, {+1, -1}, {+1,  0}, {+1, +1} };

#ifdef _DEBUG
#define debug(x) std::cout << "[" << __LINE__ << "] " << #x << ": " << x << std::endl
#else
#define debug(x)
#endif

template < class container > void concat(container& a, const container& b) {
    a.insert(std::end(a), std::begin(b), std::end(b));
}
std::vector<size_type> iota(const size_type n) {
    std::vector<size_type> I(n);
    std::iota(std::begin(I), std::end(I), 0);
    return I;
}
template < class container > std::vector<size_type> sort_idx(const container& a) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return a[i] < a[j] or (a[i] == a[j] and i < j); });
    return I;
}
template < class container, class compare > std::vector<size_type> sort_idx(const container& a, const compare& cmp) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return cmp(a[i], a[j]) or (a[i] == a[j] and i < j); });
    return std::move(I);
}

struct grid {
    using size_type = int;
    size_type H, W;
    grid(const size_type H, const size_type W) : H(H), W(W) {}
    bool contains(const size_type i, const size_type j) {
        return 0 <= i and i < H and 0 <= j and j < W;
    }
};

using f64 = long double;

template < class T > vector< T >& operator++(vector< T >& a) { for(T& x : a) x++; return a; }
template < class T > vector< T >& operator--(vector< T >& a) { for(T& x : a) x--; return a; }
template < class T > vector< T >  operator++(vector< T >& a, signed) { vector< T > res = a; for(T& x : a) x++; return res; }
template < class T > vector< T >  operator--(vector< T >& a, signed) { vector< T > res = a; for(T& x : a) x--; return res; }

} // namespace macro

using namespace macro;
#line 2 "cp-library/src/number/rational.hpp"

template < class integer > struct rational {
    integer sign, upper, lower;
    rational(const integer sign, const integer upper, const integer lower) : sign(sign), upper(upper), lower(lower) { reduce(); }
    rational(const integer upper, const integer lower) {
        if(upper == 0 and lower == 0) {
            cerr << "0/0 is not defined" << endl;
            exit(1);
        } else if(upper == 0) {
            this->sign = 1;
            this->upper = 0;
            this->lower = 1;
        } else if(lower == 0) {
            this->sign = 1;
            this->upper = 1;
            this->lower = 0;
        } else {
            const integer upper_sign = upper > 0 ? +1 : -1;
            const integer lower_sign = lower > 0 ? +1 : -1;
            this->sign = upper_sign * lower_sign;
            this->upper = upper_sign * upper;
            this->lower = lower_sign * lower;
            reduce();
        }
    }
    rational(const integer n) : rational(n, 1) {}

    friend rational operator+(const rational& a) { return rational(+a.sign, a.upper, a.lower); }
    friend rational operator-(const rational& a) { return rational(-a.sign, a.upper, a.lower); }
    friend rational operator+(const rational& a, const rational& b) { return rational((a.sign * a.upper) * b.lower + a.lower * (b.sign * b.upper), a.lower * b.lower); }
    friend rational operator-(const rational& a, const rational& b) { return rational((a.sign * a.upper) * b.lower - a.lower * (b.sign * b.upper), a.lower * b.lower); }
    friend rational operator*(const rational& a, const rational& b) { return rational(a.sign * b.sign, a.upper * b.upper, a.lower * b.lower); }
    friend rational operator/(const rational& a, const rational& b) { return rational(a.sign * b.sign, a.upper * b.lower, a.lower * b.upper); }
    friend bool operator==(const rational& a, const rational& b) { return a.sign == b.sign and a.upper == b.upper and a.lower == b.lower; }
    friend bool operator!=(const rational& a, const rational& b) { return a.sign != b.sign or  a.upper != b.upper or  a.lower != b.lower; }
    friend bool operator<(const rational& a, const rational& b) {
        if(a.sign != b.sign)
            return a.sign == -1;
        else
            return (a.sign == -1) ^ (a.upper * b.lower < b.upper * a.lower);
    }
    rational& operator+=(const rational& r) { *this = *this + r; }
    rational& operator-=(const rational& r) { *this = *this - r; }
    rational& operator*=(const rational& r) { *this = *this * r; }
    rational& operator/=(const rational& r) { *this = *this / r; }

    friend std::ostream &operator<<(std::ostream& os, const rational& a) {
        os << (a.sign * a.upper) << "/" << a.lower;
        return os;
    }

  private:
    // for i128, boost::mp
    integer gcd(const integer a, const integer b) const {
        if(b == 0) return a;
        return gcd(b, a % b);
    }
    void reduce() {
        integer g = gcd(upper, lower);
        if(g != 0) {
            upper /= g;
            lower /= g;
        }
    }
};
#line 2 "cp-library/src/number/modint.hpp"
struct modinfo { uint mod, root, isprime; };
template < modinfo const &ref >
struct modint {
    static constexpr uint const &mod = ref.mod;
    static constexpr uint const &root = ref.root;
    static constexpr uint const &isprime = ref.isprime;
    uint v = 0;
    constexpr modint& s(uint v) { this->v = v < mod ? v : v - mod; return *this; }
    constexpr modint(ll v = 0) { s(v % mod + mod); }
    modint operator-() const { return modint() - *this; }
    modint& operator+=(const modint& rhs) { return s(v + rhs.v); }
    modint& operator-=(const modint& rhs) { return s(v + mod - rhs.v); }
    modint& operator*=(const modint& rhs) { v = ull(v) * rhs.v % mod; return *this; }
    modint& operator/=(const modint& rhs) { return *this *= inv(rhs); }
    modint operator+(const modint& rhs) const { return modint(*this) += rhs; }
    modint operator-(const modint& rhs) const { return modint(*this) -= rhs; }
    modint operator*(const modint& rhs) const { return modint(*this) *= rhs; }
    modint operator/(const modint& rhs) const { return modint(*this) /= rhs; }
    friend modint pow(modint x, ll n) { modint res(1); while(n > 0) { if(n & 1) res *= x; x *= x; n >>= 1; } return res; }
    friend modint inv(modint v) {
        if(isprime) {
            return pow(v, mod - 2);
        } else {
            ll a = v.v, b = modint::mod, x = 1, y = 0, t;
            while(b > 0) { t = a / b; swap(a -= t * b, b); swap(x -= t * y, y); }
            return modint(x);
        }
    }
    friend modint operator+(int x, const modint& y) { return modint(x) + y; }
    friend modint operator-(int x, const modint& y) { return modint(x) - y; }
    friend modint operator*(int x, const modint& y) { return modint(x) * y; }
    friend modint operator/(int x, const modint& y) { return modint(x) / y; }
    friend istream& operator>>(istream& is, modint& m) { ll x; is >> x; m = modint(x); return is; }
    friend ostream& operator<<(ostream& os, const modint& m) { return os << m.v; }
    bool operator==(const modint& r) const { return v == r.v; }
    bool operator!=(const modint& r) const { return v != r.v; }
    static uint get_mod() { return mod; }
    static int is_prime() { return isprime; }
};
constexpr modinfo base998244353 { 998244353, 3, 1 };
constexpr modinfo base1000000007 { 1000000007, 0, 1 };
using mint998244353 = modint< base998244353 >;
using mint1000000007 = modint< base1000000007 >;
#line 5 "A.cpp"
using mint = mint1000000007;
using T = i128;
using F = rational< T >;
struct S { F a, b; };
const F F0 = F(0);
const F F1 = F(1);

vector<mint> solve(int N) {
    vector<pair<S, S>> seg;
    for(int i : rep(N)) {
        auto read = [&]() {
            int x = in(), y = in();
            return S{F(1, y), F(1, x)};
        };
        seg.push_back({read(), read()});
    }

    vector< F > A;
    A.push_back(F0);
    A.push_back(F1);
    {
        vector< S > ss;
        for(const pair<S, S>& s : seg) {
            ss.push_back(s.first);
            ss.push_back(s.second);
            A.push_back(s.first .a);
            A.push_back(s.second.a);
        }
        for(const S& s1 : ss) for(const S& s2 : ss) {
            if(make_pair(s1.a, s1.b) == make_pair(s2.a, s2.b)) continue;
            if(s1.a == s2.a) {
                A.push_back(s1.a);
            } else if(s1.b == s2.b) {
                A.push_back(s1.b);
            } else if((s1.a < s2.a) != (s1.b < s2.b)) {
                F U = s1.a * s2.a * (s1.b - s2.b);
                F L = s2.a * s1.b - s1.a * s2.b;
                A.push_back(U / L);
            }
        }
    }
    unique(A);

    vector<mint> ans(N + 1, 0);
    for(int i : rep(int(A.size()) - 1)) {
        const F L = A[i], R = A[i + 1];
        map<pair<F, F>, int> event;
        for(const pair<S, S>& s : seg) {
            auto get_b = [&](const S& s, F a) {
                return s.b * (F1 - a / s.a);
            };
            auto get_seg = [&](const S& s) -> pair<F, F> {
                F Lb = min(max(get_b(s, L), F0), F1);
                F Rb = min(max(get_b(s, R), F0), F1);
                return {Lb, Rb};
            };
            pair<F, F> e1 = get_seg(s.first );
            pair<F, F> e2 = get_seg(s.second);
            event[min(e1, e2)] += 1;
            event[max(e1, e2)] -= 1;
        }
        event[{F0, F0}] += 0;
        event[{F1, F1}] += 0;
        auto area = [&](const pair<F, F>& e1, const pair<F, F>& e2) -> mint {
            F s = ((e2.first - e1.first) + (e2.second - e1.second)) * (R - L) / F(2);
            return mint(i64(s.upper % T(1e9+7))) * inv(mint(i64(s.lower % T(1e9+7))));
        };
        int sum = 0;
        for(auto it = event.begin(); it != event.end(); it++) {
            sum += it->second;
            if(next(it) != event.end()) {
                ans[sum] += area(it->first, next(it)->first);
            }
        }
    }
    return ans;
}

int main() {
    while(true) {
        int N = in();
        if(N == 0) return 0;
        print(solve(N));
    }
}
accuracy: 1
time_ms: 7340
memory_kb: 4252
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;

using Real = long double;
using Point = complex<Real>;
const Real EPS = 1e-9, PI = acos(-1);

inline bool eq(Real a, Real b) {
  return fabs(b - a) < EPS;
}

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

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

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

// 平面グラフを多角形に分割する (基本的に反時計回り、外平面のみ時計回り)
// graph は単純無向グラフを想定 (u-v <=> v-u)。
// 多重辺、有向グラフなど変なグラフを入れると壊れるはず。非連結グラフは問題なし
vector<vector<int>> decompose_to_cycle(const vector<vector<int>> &graph, const vector<Point> &pos) {
  assert(graph.size() == pos.size());
  int n = graph.size();
  int m = 0;
  map<array<int, 2>, int> mp;
  vector<array<int, 2>> edge;
  for (int i = 0; i < n; ++i) {
    for (auto ni : graph[i]) {
      mp[{i, ni}] = m++;
      edge.push_back({i, ni});
    }
  }
  
  vector<int> nex(m, -1);
  for (int i = 0; i < n; ++i) {
    if (graph[i].empty()) continue;
    
    vector<pair<long double, int>> adj;
    for (int ni : graph[i]) {
      Point diff = pos[ni] - pos[i];
      assert(!eq(abs(diff), 0.0));
      adj.push_back({arg(diff), ni});
    }
    
    sort(adj.begin(), adj.end());
    int siz = adj.size();
    adj.emplace_back(adj[0]);
    adj[siz].first += 2 * PI;
    
    for (int j = 0; j < siz; ++j) {
      auto [arg0, to] = adj[j];
      auto [arg1, from] = adj[j + 1];
      int ein = mp[{from, i}];
      int eout = mp[{i, to}];
      
      nex[ein] = eout;
    }
  }
  
  vector<vector<int>> ret;
  vector<bool> used(m, false);
  for (int i = 0; i < m; ++i) {
    if (used[i]) continue;
    
    vector<int> tmp;
    int now = i;
    while (!used[now]) {
      used[now] = true;
      tmp.emplace_back(edge[now][0]);
      now = nex[now];
    }
    ret.emplace_back(tmp);
  }
  
  return ret;
}

using ll = long long;
const ll MOD = 1e9 + 7;

ll pow_mod(ll x, ll n, ll mod)
{
  ll ret = 1;
  x %= mod;
  while (n > 0)
  {
    if (n & 1) ret *= x, ret %= MOD;
    x = x * x % mod;
    n /= 2;
  }
  return ret;
}

struct Rational
{
  long long num, den;
  long long mod;
  
  Rational() = default;
  Rational(long long _num, long long _den) {
    long long g = __gcd(abs(_num), abs(_den));
    _num /= g;
    _den /= g;
    if (_den < 0 || _den == 0 && _num < 0) _num *= -1, _den *= -1;
    num = _num, den = _den;
    mod = num * pow_mod(den, MOD-2, MOD) % MOD;
  }
  
  friend ostream &operator<<(ostream &os, Rational &r) { return os << r.num << " / " << r.den; }
  
};

bool operator<(const Rational &lhs, const Rational &rhs)
{
  return lhs.num * rhs.den < rhs.num * lhs.den;
}

bool operator==(const Rational &lhs, const Rational &rhs)
{
  return lhs.num == rhs.num && lhs.den == rhs.den;
}

pair<Rational, Rational> crosspoint(ll a1, ll b1, ll a2, ll b2)
{
  ll den = a1 * b2 - a2 * b1;
  if (den == 0) return {Rational(0, 1), Rational(0, 1)};
  return {Rational(b2 - b1, den), Rational(-a2 + a1, den)};
}

// // 多角形の面積
// Real area(const Polygon &p) {
//   Real A = 0;
//   for (int i = 0; i < p.size(); ++i) {
//     A += cross(p[i], p[(i + 1) % p.size()]);
//   }
//   return A * 0.5;
// }

ll calc_area(const vector< array<Rational, 2> > &vec)
{
  ll ret = 0;
  for (int i = 0; i < vec.size(); ++i)
  {
    auto [rx0, ry0] = vec[i];
    auto [rx1, ry1] = vec[(i+1) % vec.size()];
    
    ret += (rx0.mod * ry1.mod - ry0.mod * rx1.mod);
    ret = (ret % MOD + MOD) % MOD;
  }
  if (ret % 2 == 1) ret += MOD;
  ret /= 2;
  return ret;
}

/*-- main --*/

bool is_end = false;
using ld = long double;

void insert_to_map(map<array<Rational, 2>, int> &mp, vector< array<Rational, 2> > &points, array<Rational, 2> p)
{
  if (mp.find(p) == mp.end())
  {
    mp[p] = points.size();
    points.emplace_back(p);
  }
  return;
}

void solve()
{
  ll N; cin >> N;
  if (N == 0)
  {
    is_end = true;
    return;
  }
  vector< array<Rational, 2> > points;
  map< array<Rational, 2> , int> mp;
  Rational one(1, 1), zero(0, 1);
  
  vector<array<ll, 2>> ab;
  for (int i = 0; i < N; ++i)
  {
    for (int j = 0; j < 2; ++j)
    {
      ll a, b; cin >> a >> b;
      ab.push_back({a, b});
      
      {
        Rational rx(1, a), ry(1, b);
        insert_to_map(mp, points, {rx, zero});
        insert_to_map(mp, points, {zero, ry});
      }
      
    }
  }
  
  {
    insert_to_map(mp, points, {zero, zero});
    insert_to_map(mp, points, {zero, one});
    insert_to_map(mp, points, {one, zero});
    insert_to_map(mp, points, {one, one});
  }
  
  assert((int)ab.size() == 2 * N);
  for (int i = 0; i < 2 * N; ++i)
  {
    for (int j = 0; j < 2 * N; ++j)
    {
      auto [ai, bi] = ab[i];
      auto [aj, bj] = ab[j];
      auto [rx, ry] = crosspoint(ai, bi, aj, bj);
      
      if (zero < rx && rx < one && zero < ry && ry < one)
      {
        insert_to_map(mp, points, {rx, ry});
      }
    }
  }
  // cout << points.size() << endl;
  
  vector< Point > real_points;
  vector<vector< tuple<Real, Real, int> >> ids_on_line(2 * N + 4);
  for (int i = 0; i < points.size(); ++i)
  {
    auto [rx, ry] = points[i];
    Real x = (Real)rx.num / rx.den;
    Real y = (Real)ry.num / ry.den;
    real_points.emplace_back(Point(x, y));
    auto tup = tie(x, y, i);
    
    for (int j = 0; j < 2*N; ++j)
    {
      auto [a, b] = ab[j];
      Real z = a * x + b * y - 1.0;
      if (eq(z, 0.0)) ids_on_line[j].emplace_back(tup);
    }
    
    if (eq(x, 0.0)) ids_on_line[2*N+0].emplace_back(tup);
    if (eq(x, 1.0)) ids_on_line[2*N+1].emplace_back(tup);
    if (eq(y, 0.0)) ids_on_line[2*N+2].emplace_back(tup);
    if (eq(y, 1.0)) ids_on_line[2*N+3].emplace_back(tup);
  }
  for (auto &vec : ids_on_line)
  {
    sort(vec.begin(), vec.end());
  }
  
  vector<vector<int>> graph(points.size());
  vector adj(points.size(), vector<bool>(points.size(), false));
  for (int i = 0; i < 2*N+4; ++i)
  {
    int siz = ids_on_line[i].size();
    for (int j = 0; j + 1 < siz; ++j)
    {
      auto [x0, y0, id0] = ids_on_line[i][j];
      auto [x1, y1, id1] = ids_on_line[i][j+1];
      adj[id0][id1] = adj[id1][id0] = true;
    }
  }
  for (int i = 0; i < points.size(); ++i)
  {
    for (int j = 0; j < points.size(); ++j)
    {
      if (adj[i][j]) graph[i].emplace_back(j);
    }
  }
  vector<vector<int>> polys = decompose_to_cycle(graph, real_points);
  
  int siz = polys.size();
  vector< ll > areas;
  vector< Point > centers;
  
  for (auto vec : polys)
  {
    vector< array<Rational, 2> > tmp;
    Point p(0.0, 0.0);
    for (auto id : vec)
    {
      tmp.emplace_back(points[id]);
      p += real_points[id];
      // cout << points[id][0] << ", " << points[id][1] << " | ";
      // cout << points[id][0].mod << ", " << points[id][1].mod << endl;
    }
    p /= vec.size();
    
    ll ar = calc_area(tmp);
    if (ar == MOD - 1) ar = 0;
    areas.emplace_back(ar);
    centers.emplace_back(p);
  }
  
  vector<ll> res(N+1, 0);
  for (int i = 0; i < siz; ++i)
  {
    ll cnt = 0;
    Real x = centers[i].real();
    Real y = centers[i].imag();
    for (int j = 0; j < N; ++j)
    {
      auto [a0, b0] = ab[2*j];
      auto [a1, b1] = ab[2*j+1];
      
      Real hoge = (a0 * x + b0 * y - 1) * (a1 * x + b1 * y - 1);
      if (hoge < 0.0) cnt++;
    }
    res[cnt] += areas[i];
    res[cnt] %= MOD;
  }
  
  for (int i = 0; i <= N; ++i)
  {
    cout << res[i] << " \n"[i == N];
  }
  
  return;
}

int main()
{
  while (!is_end)
  {
    solve();
  }
  
  return 0;
}
accuracy: 1
time_ms: 510
memory_kb: 6424
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;

using Real = long double;
using Point = complex<Real>;
const Real EPS = 1e-9, PI = acos(-1);

inline bool eq(Real a, Real b) {
  return fabs(b - a) < EPS;
}

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

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

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

// 点 p を反時計回りに theta 回転
Point rotate(Real theta, const Point &p) {
  return Point(
    cos(theta) * p.real() - sin(theta) * p.imag(), sin(theta) * p.real() + cos(theta) * p.imag());
}

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

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

// a-b-c の角度のうち小さい方を返す
Real get_angle(const Point &a, const Point &b, const Point &c) {
  const Point v(b - a), w(c - b);
  Real alpha = atan2(v.imag(), v.real()), beta = atan2(w.imag(), w.real());
  if (alpha > beta) swap(alpha, beta);
  Real theta = (beta - alpha);
  return min(theta, 2 * acos(-1) - theta);
}

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

struct Line {
  Point a, b;

  Line() = default;

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

  Line(Real A, Real B, Real C)  // Ax + By = 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 ostream &operator<<(ostream &os, Line &p) { return os << p.a << " to " << p.b; }

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

struct Segment : Line {
  Segment() = default;

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

struct Circle {
  Point p;
  Real r;

  Circle() = default;

  Circle(Point p, Real r) : p(p), r(r) {}
};

using Points = vector<Point>;
using Polygon = vector<Point>;
using Segments = vector<Segment>;
using Lines = vector<Line>;
using Circles = vector<Circle>;

Real cross(const Point &a, const Point &b) {
  return real(a) * imag(b) - imag(a) * real(b);
}

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

// 点の回転方向
int ccw(const Point &a, Point b, Point c) {
  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;       // "ONLINE_BACK"
  if (norm(b) < norm(c)) return -2;   // "ONLINE_FRONT"
  return 0;                           // "ON_SEGMENT"
}

// 平行判定
bool parallel(const Line &a, const Line &b) {
  return eq(cross(a.b - a.a, b.b - b.a), 0.0);
}

// 垂直判定
bool orthogonal(const Line &a, const Line &b) {
  return eq(dot(a.a - a.b, b.a - b.b), 0.0);
}

// 射影
// 直線 l に p から垂線を引いた交点を求める
Point projection(const Line &l, const Point &p) {
  double t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
  return l.a + (l.a - l.b) * t;
}
Point projection(const Segment &l, const Point &p) {
  double t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
  return l.a + (l.a - l.b) * t;
}

// 反射
// 直線 l を対称軸として点 p  と線対称にある点を求める
Point reflection(const Line &l, const Point &p) {
  return p + (projection(l, p) - p) * 2.0;
}

bool intersect(const Line &l, const Point &p) {
  return abs(ccw(l.a, l.b, p)) != 1;
}
bool intersect(const Line &l, const Line &m) {
  return abs(cross(l.b - l.a, m.b - m.a)) > EPS || abs(cross(l.b - l.a, m.b - l.a)) < EPS;
}
bool intersect(const Segment &s, const Point &p) {
  return ccw(s.a, s.b, p) == 0;
}
bool intersect(const Line &l, const Segment &s) {
  return cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < EPS;
}

Real distance(const Line &l, const Point &p);

bool intersect(const Circle &c, const Line &l) {
  return distance(l, c.p) <= c.r + EPS;
}
bool intersect(const Circle &c, const Point &p) {
  return abs(abs(p - c.p) - c.r) < EPS;
}
bool intersect(const Segment &s, const Segment &t) {
  return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
         ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

int intersect(const Circle &c, const Segment &l) {
  if (norm(projection(l, c.p) - c.p) - c.r * c.r > EPS) return 0;
  auto d1 = abs(c.p - l.a), d2 = abs(c.p - l.b);
  if (d1 < c.r + EPS && d2 < c.r + EPS) return 0;
  if (d1 < c.r - EPS && d2 > c.r + EPS || d1 > c.r + EPS && d2 < c.r - EPS) return 1;
  const Point h = projection(l, c.p);
  if (dot(l.a - h, l.b - h) < 0) return 2;
  return 0;
}
// 0 -> 包含, 1 -> 内接, 2 -> 交差, 3 -> 外接, 4 -> 分離
int intersect(Circle c1, Circle c2) {
  if (c1.r < c2.r) swap(c1, c2);
  Real d = abs(c1.p - c2.p);
  if (c1.r + c2.r < d) return 4;
  if (eq(c1.r + c2.r, d)) return 3;
  if (c1.r - c2.r < d) return 2;
  if (eq(c1.r - c2.r, d)) return 1;
  return 0;
}

Real distance(const Point &a, const Point &b) {
  return abs(a - b);
}
Real distance(const Line &l, const Point &p) {
  return abs(p - projection(l, p));
}
Real distance(const Line &l, const Line &m) {
  return intersect(l, m) ? 0 : distance(l, m.a);
}
Real distance(const Segment &s, const Point &p) {
  Point r = projection(s, p);
  if (intersect(s, r)) return abs(r - p);
  return min(abs(s.a - p), abs(s.b - p));
}
Real distance(const Segment &a, const Segment &b) {
  if (intersect(a, b)) return 0;
  return min({distance(a, b.a), distance(a, b.b), distance(b, a.a), distance(b, a.b)});
}
Real distance(const Line &l, const Segment &s) {
  if (intersect(l, s)) return 0;
  return min(distance(l, s.a), distance(l, s.b));
}

Point crosspoint(const Line &l, const Line &m) {
  Real A = cross(l.b - l.a, m.b - m.a);
  Real B = cross(l.b - l.a, l.b - m.a);
  if (eq(abs(A), 0.0) && eq(abs(B), 0.0)) return m.a;
  return m.a + (m.b - m.a) * B / A;
}
Point crosspoint(const Segment &l, const Segment &m) {
  return crosspoint(Line(l), Line(m));
}
pair<Point, Point> crosspoint(const Circle &c, const Line l) {
  Point pr = projection(l, c.p);
  Point e = (l.b - l.a) / abs(l.b - l.a);
  if (eq(distance(l, c.p), c.r)) return {pr, pr};
  double base = sqrt(c.r * c.r - norm(pr - c.p));
  return {pr - e * base, pr + e * base};
}
pair<Point, Point> crosspoint(const Circle &c, const Segment &l) {
  Line aa = Line(l.a, l.b);
  if (intersect(c, l) == 2) return crosspoint(c, aa);
  auto ret = crosspoint(c, aa);
  if (dot(l.a - ret.first, l.b - ret.first) < 0) ret.second = ret.first;
  else ret.first = ret.second;
  return ret;
}
pair<Point, Point> crosspoint(const Circle &c1, const Circle &c2) {
  Real d = abs(c1.p - c2.p);
  Real a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
  Real t = atan2(c2.p.imag() - c1.p.imag(), c2.p.real() - c1.p.real());
  Point p1 = c1.p + Point(cos(t + a) * c1.r, sin(t + a) * c1.r);
  Point p2 = c1.p + Point(cos(t - a) * c1.r, sin(t - a) * c1.r);
  return {p1, p2};
}

// 点 p を通る円 c の接線
pair<Point, Point> tangent(const Circle &c1, const Point &p2) {
  return crosspoint(c1, Circle(p2, sqrt(norm(c1.p - p2) - c1.r * c1.r)));
}

// 円 c1, c2 の共通接線
Lines tangent(Circle c1, Circle c2) {
  Lines ret;
  if (c1.r < c2.r) swap(c1, c2);
  Real g = norm(c1.p - c2.p);
  if (eq(g, 0)) return ret;
  Point u = (c2.p - c1.p) / sqrt(g);
  Point v = rotate(PI * 0.5, u);
  for (int s : {-1, 1}) {
    Real h = (c1.r + s * c2.r) / sqrt(g);
    if (eq(1 - h * h, 0)) {
      ret.emplace_back(c1.p + u * c1.r, c1.p + (u + v) * c1.r);
    } else if (1 - h * h > 0) {
      Point uu = u * h, vv = v * sqrt(1 - h * h);
      ret.emplace_back(c1.p + (uu + vv) * c1.r, c2.p - (uu + vv) * c2.r * s);
      ret.emplace_back(c1.p + (uu - vv) * c1.r, c2.p - (uu - vv) * c2.r * s);
    }
  }
  return ret;
}

// 凸性判定
bool is_convex(const Polygon &p) {
  int n = (int)p.size();
  for (int i = 0; i < n; i++) {
    if (ccw(p[(i + n - 1) % n], p[i], p[(i + 1) % n]) == -1) return false;
  }
  return true;
}

// 凸包
Polygon convex_hull(Polygon &p) {
  int n = (int)p.size(), k = 0;
  if (n <= 2) return p;
  sort(p.begin(), p.end());
  vector<Point> ch(2 * n);
  for (int i = 0; i < n; ch[k++] = p[i++]) {
    while (k >= 2 && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS) --k;
  }
  for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) {
    while (k >= t && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS) --k;
  }
  ch.resize(k - 1);
  return ch;
}

// 多角形と点の包含判定
enum { OUT, ON, IN };

int contains(const Polygon &Q, const Point &p) {
  bool in = false;
  for (int i = 0; i < Q.size(); i++) {
    Point a = Q[i] - p, b = Q[(i + 1) % Q.size()] - p;
    if (a.imag() > b.imag()) swap(a, b);
    if (a.imag() <= 0 && 0 < b.imag() && cross(a, b) < 0) in = !in;
    if (cross(a, b) == 0 && dot(a, b) <= 0) return ON;
  }
  return in ? IN : OUT;
}

// 線分の重複除去
void merge_segments(vector<Segment> &segs) {
  auto merge_if_able = [](Segment &s1, const Segment &s2) {
    if (abs(cross(s1.b - s1.a, s2.b - s2.a)) > EPS) return false;
    if (ccw(s1.a, s2.a, s1.b) == 1 || ccw(s1.a, s2.a, s1.b) == -1) return false;
    if (ccw(s1.a, s1.b, s2.a) == -2 || ccw(s2.a, s2.b, s1.a) == -2) return false;
    s1 = Segment(min(s1.a, s2.a), max(s1.b, s2.b));
    return true;
  };

  for (int i = 0; i < segs.size(); i++) {
    if (segs[i].b < segs[i].a) swap(segs[i].a, segs[i].b);
  }
  for (int i = 0; i < segs.size(); i++) {
    for (int j = i + 1; j < segs.size(); j++) {
      if (merge_if_able(segs[i], segs[j])) {
        segs[j--] = segs.back(), segs.pop_back();
      }
    }
  }
}

// 線分アレンジメント
// 任意の2線分の交点を頂点としたグラフを構築する
vector<vector<int>> segment_arrangement(vector<Segment> &segs, vector<Point> &ps) {
  vector<vector<int>> g;
  int N = (int)segs.size();
  for (int i = 0; i < N; i++) {
    ps.emplace_back(segs[i].a);
    ps.emplace_back(segs[i].b);
    for (int j = i + 1; j < N; j++) {
      const Point p1 = segs[i].b - segs[i].a;
      const Point p2 = segs[j].b - segs[j].a;
      if (cross(p1, p2) == 0) continue;
      if (intersect(segs[i], segs[j])) {
        ps.emplace_back(crosspoint(segs[i], segs[j]));
      }
    }
  }
  sort(begin(ps), end(ps));
  ps.erase(unique(begin(ps), end(ps)), end(ps));

  int M = (int)ps.size();
  g.resize(M);
  for (int i = 0; i < N; i++) {
    vector<int> vec;
    for (int j = 0; j < M; j++) {
      if (intersect(segs[i], ps[j])) {
        vec.emplace_back(j);
      }
    }
    for (int j = 1; j < vec.size(); j++) {
      g[vec[j - 1]].push_back(vec[j]);
      g[vec[j]].push_back(vec[j - 1]);
    }
  }
  return (g);
}

// 凸多角形の切断
// 直線 l.a-l.b で切断しその左側にできる凸多角形を返す
Polygon convex_cut(const Polygon &U, Line l) {
  Polygon ret;
  for (int i = 0; i < U.size(); i++) {
    Point now = U[i], nxt = U[(i + 1) % U.size()];
    if (ccw(l.a, l.b, now) != -1) ret.push_back(now);
    if (ccw(l.a, l.b, now) * ccw(l.a, l.b, nxt) < 0) {
      ret.push_back(crosspoint(Line(now, nxt), l));
    }
  }
  return (ret);
}

// 多角形の面積
Real area(const Polygon &p) {
  Real A = 0;
  for (int i = 0; i < p.size(); ++i) {
    A += cross(p[i], p[(i + 1) % p.size()]);
  }
  return A * 0.5;
}

// 円と多角形の共通部分の面積
Real area(const Polygon &p, const Circle &c) {
  if (p.size() < 3) return 0.0;
  function<Real(Circle, Point, Point)> cross_area = [&](const Circle &c, const Point &a,
                                                      const Point &b) {
    Point va = c.p - a, vb = c.p - b;
    Real f = cross(va, vb), ret = 0.0;
    if (eq(f, 0.0)) return ret;
    if (max(abs(va), abs(vb)) < c.r + EPS) return f;
    if (distance(Segment(a, b), c.p) > c.r - EPS) return c.r * c.r * arg(vb * conj(va));
    auto u = crosspoint(c, Segment(a, b));
    vector<Point> tot{a, u.first, u.second, b};
    for (int i = 0; i + 1 < tot.size(); i++) {
      ret += cross_area(c, tot[i], tot[i + 1]);
    }
    return ret;
  };
  Real A = 0;
  for (int i = 0; i < p.size(); i++) {
    A += cross_area(c, p[i], p[(i + 1) % p.size()]);
  }
  return A;
}

// 凸多角形の直径(最遠頂点対間距離)
Real convex_diameter(const Polygon &p) {
  int N = (int)p.size();
  int is = 0, js = 0;
  for (int i = 1; i < N; i++) {
    if (p[i].imag() > p[is].imag()) is = i;
    if (p[i].imag() < p[js].imag()) js = i;
  }
  Real maxdis = norm(p[is] - p[js]);

  int maxi, maxj, i, j;
  i = maxi = is;
  j = maxj = js;
  do {
    if (cross(p[(i + 1) % N] - p[i], p[(j + 1) % N] - p[j]) >= 0) {
      j = (j + 1) % N;
    } else {
      i = (i + 1) % N;
    }
    if (norm(p[i] - p[j]) > maxdis) {
      maxdis = norm(p[i] - p[j]);
      maxi = i;
      maxj = j;
    }
  } while (i != is || j != js);
  return sqrt(maxdis);
}

// 最近点対
Real closest_pair(Points ps) {
  if (ps.size() <= 1) throw(0);
  sort(begin(ps), end(ps));

  auto compare_y = [&](const Point &a, const Point &b) { return imag(a) < imag(b); };
  vector<Point> beet(ps.size());
  const Real INF = 1e18;

  function<Real(int, int)> rec = [&](int left, int right) {
    if (right - left <= 1) return INF;
    int mid = (left + right) >> 1;
    auto x = real(ps[mid]);
    auto ret = min(rec(left, mid), rec(mid, right));
    inplace_merge(begin(ps) + left, begin(ps) + mid, begin(ps) + right, compare_y);
    int ptr = 0;
    for (int i = left; i < right; i++) {
      if (abs(real(ps[i]) - x) >= ret) continue;
      for (int j = 0; j < ptr; j++) {
        auto luz = ps[i] - beet[ptr - j - 1];
        if (imag(luz) >= ret) break;
        ret = min(ret, abs(luz));
      }
      beet[ptr++] = ps[i];
    }
    return ret;
  };
  return rec(0, (int)ps.size());
}

// 平面グラフを多角形に分割する (基本的に反時計回り、外平面のみ時計回り)
// graph は単純無向グラフを想定 (u-v <=> v-u)。
// 多重辺、有向グラフなど変なグラフを入れると壊れるはず。非連結グラフは問題なし
vector<vector<int>> decompose_to_cycle(const vector<vector<int>> &graph, const vector<Point> &pos) {
  assert(graph.size() == pos.size());
  int n = graph.size();
  int m = 0;
  map<array<int, 2>, int> mp;
  vector<array<int, 2>> edge;
  for (int i = 0; i < n; ++i) {
    for (auto ni : graph[i]) {
      mp[{i, ni}] = m++;
      edge.push_back({i, ni});
    }
  }
  
  vector<int> nex(m, -1);
  for (int i = 0; i < n; ++i) {
    if (graph[i].empty()) continue;
    
    vector<pair<long double, int>> adj;
    for (int ni : graph[i]) {
      Point diff = pos[ni] - pos[i];
      assert(!eq(abs(diff), 0.0));
      adj.push_back({arg(diff), ni});
    }
    
    sort(adj.begin(), adj.end());
    int siz = adj.size();
    adj.emplace_back(adj[0]);
    adj[siz].first += 2 * PI;
    
    for (int j = 0; j < siz; ++j) {
      auto [arg0, to] = adj[j];
      auto [arg1, from] = adj[j + 1];
      int ein = mp[{from, i}];
      int eout = mp[{i, to}];
      
      nex[ein] = eout;
    }
  }
  
  vector<vector<int>> ret;
  vector<bool> used(m, false);
  for (int i = 0; i < m; ++i) {
    if (used[i]) continue;
    
    vector<int> tmp;
    int now = i;
    while (!used[now]) {
      used[now] = true;
      tmp.emplace_back(edge[now][0]);
      now = nex[now];
    }
    ret.emplace_back(tmp);
  }
  
  return ret;
}

using ll = long long;
const ll MOD = 1e9 + 7;

ll pow_mod(ll x, ll n, ll mod)
{
  ll ret = 1;
  x %= mod;
  while (n > 0)
  {
    if (n & 1) ret *= x, ret %= MOD;
    x = x * x % mod;
    n /= 2;
  }
  return ret;
}

struct Rational
{
  long long num, den;
  long long mod;
  
  Rational() = default;
  Rational(long long _num, long long _den) {
    long long g = __gcd(abs(_num), abs(_den));
    _num /= g;
    _den /= g;
    if (_den < 0 || _den == 0 && _num < 0) _num *= -1, _den *= -1;
    num = _num, den = _den;
    mod = num * pow_mod(den, MOD-2, MOD) % MOD;
  }
  
  friend ostream &operator<<(ostream &os, Rational &r) { return os << r.num << " / " << r.den; }
  
};

bool operator<(const Rational &lhs, const Rational &rhs)
{
  return lhs.num * rhs.den < rhs.num * lhs.den;
}

bool operator==(const Rational &lhs, const Rational &rhs)
{
  return lhs.num == rhs.num && lhs.den == rhs.den;
}

pair<Rational, Rational> crosspoint(ll a1, ll b1, ll a2, ll b2)
{
  ll den = a1 * b2 - a2 * b1;
  if (den == 0) return {Rational(0, 1), Rational(0, 1)};
  return {Rational(b2 - b1, den), Rational(-a2 + a1, den)};
}

// // 多角形の面積
// Real area(const Polygon &p) {
//   Real A = 0;
//   for (int i = 0; i < p.size(); ++i) {
//     A += cross(p[i], p[(i + 1) % p.size()]);
//   }
//   return A * 0.5;
// }

ll calc_area(const vector< array<Rational, 2> > &vec)
{
  ll ret = 0;
  for (int i = 0; i < vec.size(); ++i)
  {
    auto [rx0, ry0] = vec[i];
    auto [rx1, ry1] = vec[(i+1) % vec.size()];
    
    ret += (rx0.mod * ry1.mod - ry0.mod * rx1.mod);
    ret = (ret % MOD + MOD) % MOD;
  }
  if (ret % 2 == 1) ret += MOD;
  ret /= 2;
  return ret;
}

/*-- main --*/

bool is_end = false;
using ld = long double;

void insert_to_map(map<array<Rational, 2>, int> &mp, vector< array<Rational, 2> > &points, array<Rational, 2> p)
{
  if (mp.find(p) == mp.end())
  {
    mp[p] = points.size();
    points.emplace_back(p);
  }
  return;
}

void solve()
{
  ll N; cin >> N;
  if (N == 0)
  {
    is_end = true;
    return;
  }
  vector< array<Rational, 2> > points;
  map< array<Rational, 2> , int> mp;
  Rational one(1, 1), zero(0, 1);
  
  vector<Line> lines;
  vector<array<ll, 2>> ab;
  for (int i = 0; i < N; ++i)
  {
    for (int j = 0; j < 2; ++j)
    {
      ll a, b; cin >> a >> b;
      ab.push_back({a, b});
      lines.emplace_back(Line( Point((ld)1.0 / a, 0), Point(0, (ld)1.0 / b) ));
      
      {
        Rational rx(1, a), ry(1, b);
        insert_to_map(mp, points, {rx, zero});
        insert_to_map(mp, points, {zero, ry});
      }
      
    }
  }
  
  {
    insert_to_map(mp, points, {zero, zero});
    insert_to_map(mp, points, {zero, one});
    insert_to_map(mp, points, {one, zero});
    insert_to_map(mp, points, {one, one});
  }
  
  assert((int)ab.size() == 2 * N);
  for (int i = 0; i < 2 * N; ++i)
  {
    for (int j = 0; j < 2 * N; ++j)
    {
      auto [ai, bi] = ab[i];
      auto [aj, bj] = ab[j];
      auto [rx, ry] = crosspoint(ai, bi, aj, bj);
      
      if (zero < rx && rx < one && zero < ry && ry < one)
      {
        insert_to_map(mp, points, {rx, ry});
      }
    }
  }
  // cout << points.size() << endl;
  
  vector< Point > real_points;
  vector<vector< tuple<Real, Real, int> >> ids_on_line(2 * N + 4);
  for (int i = 0; i < points.size(); ++i)
  {
    auto [rx, ry] = points[i];
    Real x = (Real)rx.num / rx.den;
    Real y = (Real)ry.num / ry.den;
    real_points.emplace_back(Point(x, y));
    auto tup = tie(x, y, i);
    
    for (int j = 0; j < 2*N; ++j)
    {
      auto [a, b] = ab[j];
      Real z = a * x + b * y - 1.0;
      if (eq(z, 0.0)) ids_on_line[j].emplace_back(tup);
    }
    
    if (eq(x, 0.0)) ids_on_line[2*N+0].emplace_back(tup);
    if (eq(x, 1.0)) ids_on_line[2*N+1].emplace_back(tup);
    if (eq(y, 0.0)) ids_on_line[2*N+2].emplace_back(tup);
    if (eq(y, 1.0)) ids_on_line[2*N+3].emplace_back(tup);
  }
  for (auto &vec : ids_on_line)
  {
    sort(vec.begin(), vec.end());
  }
  
  vector<vector<int>> graph(points.size());
  vector adj(points.size(), vector<bool>(points.size(), false));
  for (int i = 0; i < 2*N+4; ++i)
  {
    int siz = ids_on_line[i].size();
    for (int j = 0; j + 1 < siz; ++j)
    {
      auto [x0, y0, id0] = ids_on_line[i][j];
      auto [x1, y1, id1] = ids_on_line[i][j+1];
      adj[id0][id1] = adj[id1][id0] = true;
    }
  }
  for (int i = 0; i < points.size(); ++i)
  {
    for (int j = 0; j < points.size(); ++j)
    {
      if (adj[i][j]) graph[i].emplace_back(j);
    }
  }
  vector<vector<int>> polys = decompose_to_cycle(graph, real_points);
  
  int siz = polys.size();
  vector< ll > areas;
  vector< Point > centers;
  
  for (auto vec : polys)
  {
    vector< array<Rational, 2> > tmp;
    Point p(0.0, 0.0);
    for (auto id : vec)
    {
      tmp.emplace_back(points[id]);
      p += real_points[id];
      // cout << points[id][0] << ", " << points[id][1] << " | ";
      // cout << points[id][0].mod << ", " << points[id][1].mod << endl;
    }
    p /= vec.size();
    
    ll ar = calc_area(tmp);
    if (ar == MOD - 1) ar = 0;
    areas.emplace_back(ar);
    centers.emplace_back(p);
  }
  
  vector<ll> res(N+1, 0);
  for (int i = 0; i < siz; ++i)
  {
    ll cnt = 0;
    Real x = centers[i].real();
    Real y = centers[i].imag();
    for (int j = 0; j < N; ++j)
    {
      auto [a0, b0] = ab[2*j];
      auto [a1, b1] = ab[2*j+1];
      
      Real hoge = (a0 * x + b0 * y - 1) * (a1 * x + b1 * y - 1);
      if (hoge < 0.0) cnt++;
    }
    res[cnt] += areas[i];
    res[cnt] %= MOD;
  }
  
  for (int i = 0; i <= N; ++i)
  {
    cout << res[i] << " \n"[i == N];
  }
  
  return;
}

int main()
{
  while (!is_end)
  {
    solve();
  }
  
  return 0;
}
accuracy: 1
time_ms: 500
memory_kb: 6308
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=105,INF=1<<30;

ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}

//modintのみ

// from: https://gist.github.com/yosupo06/ddd51afb727600fd95d9d8ad6c3c80c9
// (based on AtCoder STL)

#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {
    
    namespace internal {
        
#ifndef _MSC_VER
        template <class T>
        using is_signed_int128 =
        typename std::conditional<std::is_same<T, __int128_t>::value ||
        std::is_same<T, __int128>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_unsigned_int128 =
        typename std::conditional<std::is_same<T, __uint128_t>::value ||
        std::is_same<T, unsigned __int128>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using make_unsigned_int128 =
        typename std::conditional<std::is_same<T, __int128_t>::value,
        __uint128_t,
        unsigned __int128>;
        
        template <class T>
        using is_integral = typename std::conditional<std::is_integral<T>::value ||
        is_signed_int128<T>::value ||
        is_unsigned_int128<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                         std::is_signed<T>::value) ||
        is_signed_int128<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_unsigned_int =
        typename std::conditional<(is_integral<T>::value &&
                                   std::is_unsigned<T>::value) ||
        is_unsigned_int128<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using to_unsigned = typename std::conditional<
        is_signed_int128<T>::value,
        make_unsigned_int128<T>,
        typename std::conditional<std::is_signed<T>::value,
        std::make_unsigned<T>,
        std::common_type<T>>::type>::type;
        
#else
        
        template <class T> using is_integral = typename std::is_integral<T>;
        
        template <class T>
        using is_signed_int =
        typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_unsigned_int =
        typename std::conditional<is_integral<T>::value &&
        std::is_unsigned<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using to_unsigned = typename std::conditional<is_signed_int<T>::value,
        std::make_unsigned<T>,
        std::common_type<T>>::type;
        
#endif
        
        template <class T>
        using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;
        
        template <class T>
        using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;
        
        template <class T> using to_unsigned_t = typename to_unsigned<T>::type;
        
    }  // namespace internal
    
}  // namespace atcoder

#include <utility>

namespace atcoder {
    
    namespace internal {
        
        constexpr long long safe_mod(long long x, long long m) {
            x %= m;
            if (x < 0) x += m;
            return x;
        }
        
        struct barrett {
            unsigned int _m;
            unsigned long long im;
            
            barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}
            
            unsigned int umod() const { return _m; }
            
            unsigned int mul(unsigned int a, unsigned int b) const {
                
                unsigned long long z = a;
                z *= b;
#ifdef _MSC_VER
                unsigned long long x;
                _umul128(z, im, &x);
#else
                unsigned long long x =
                (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
                unsigned int v = (unsigned int)(z - x * _m);
                if (_m <= v) v += _m;
                return v;
            }
        };
        
        constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
            if (m == 1) return 0;
            unsigned int _m = (unsigned int)(m);
            unsigned long long r = 1;
            unsigned long long y = safe_mod(x, m);
            while (n) {
                if (n & 1) r = (r * y) % _m;
                y = (y * y) % _m;
                n >>= 1;
            }
            return r;
        }
        
        constexpr bool is_prime_constexpr(int n) {
            if (n <= 1) return false;
            if (n == 2 || n == 7 || n == 61) return true;
            if (n % 2 == 0) return false;
            long long d = n - 1;
            while (d % 2 == 0) d /= 2;
            for (long long a : {2, 7, 61}) {
                long long t = d;
                long long y = pow_mod_constexpr(a, t, n);
                while (t != n - 1 && y != 1 && y != n - 1) {
                    y = y * y % n;
                    t <<= 1;
                }
                if (y != n - 1 && t % 2 == 0) {
                    return false;
                }
            }
            return true;
        }
        template <int n> constexpr bool is_prime = is_prime_constexpr(n);
        
        constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
            a = safe_mod(a, b);
            if (a == 0) return {b, 0};
            
            long long s = b, t = a;
            long long m0 = 0, m1 = 1;
            
            while (t) {
                long long u = s / t;
                s -= t * u;
                m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b
                
                
                auto tmp = s;
                s = t;
                t = tmp;
                tmp = m0;
                m0 = m1;
                m1 = tmp;
            }
            if (m0 < 0) m0 += b / s;
            return {s, m0};
        }
        
        constexpr int primitive_root_constexpr(int m) {
            if (m == 2) return 1;
            if (m == 167772161) return 3;
            if (m == 469762049) return 3;
            if (m == 754974721) return 11;
            if (m == 998244353) return 3;
            int divs[20] = {};
            divs[0] = 2;
            int cnt = 1;
            int x = (m - 1) / 2;
            while (x % 2 == 0) x /= 2;
            for (int i = 3; (long long)(i)*i <= x; i += 2) {
                if (x % i == 0) {
                    divs[cnt++] = i;
                    while (x % i == 0) {
                        x /= i;
                    }
                }
            }
            if (x > 1) {
                divs[cnt++] = x;
            }
            for (int g = 2;; g++) {
                bool ok = true;
                for (int i = 0; i < cnt; i++) {
                    if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                        ok = false;
                        break;
                    }
                }
                if (ok) return g;
            }
        }
        template <int m> constexpr int primitive_root = primitive_root_constexpr(m);
        
    }  // namespace internal
    
}  // namespace atcoder

#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {
    
    namespace internal {
        
        struct modint_base {};
        struct static_modint_base : modint_base {};
        
        template <class T> using is_modint = std::is_base_of<modint_base, T>;
        template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;
        
    }  // namespace internal
    
    template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
    struct static_modint : internal::static_modint_base {
        using mint = static_modint;
        
    public:
        static constexpr int mod() { return m; }
        static mint raw(int v) {
            mint x;
            x._v = v;
            return x;
        }
        
        static_modint() : _v(0) {}
        template <class T, internal::is_signed_int_t<T>* = nullptr>
        static_modint(T v) {
            long long x = (long long)(v % (long long)(umod()));
            if (x < 0) x += umod();
            _v = (unsigned int)(x);
        }
        template <class T, internal::is_unsigned_int_t<T>* = nullptr>
        static_modint(T v) {
            _v = (unsigned int)(v % umod());
        }
        static_modint(bool v) { _v = ((unsigned int)(v) % umod()); }
        
        unsigned int val() const { return _v; }
        
        mint& operator++() {
            _v++;
            if (_v == umod()) _v = 0;
            return *this;
        }
        mint& operator--() {
            if (_v == 0) _v = umod();
            _v--;
            return *this;
        }
        mint operator++(int) {
            mint result = *this;
            ++*this;
            return result;
        }
        mint operator--(int) {
            mint result = *this;
            --*this;
            return result;
        }
        
        mint& operator+=(const mint& rhs) {
            _v += rhs._v;
            if (_v >= umod()) _v -= umod();
            return *this;
        }
        mint& operator-=(const mint& rhs) {
            _v -= rhs._v;
            if (_v >= umod()) _v += umod();
            return *this;
        }
        mint& operator*=(const mint& rhs) {
            unsigned long long z = _v;
            z *= rhs._v;
            _v = (unsigned int)(z % umod());
            return *this;
        }
        mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }
        
        mint operator+() const { return *this; }
        mint operator-() const { return mint() - *this; }
        
        mint pow(long long n) const {
            assert(0 <= n);
            mint x = *this, r = 1;
            while (n) {
                if (n & 1) r *= x;
                x *= x;
                n >>= 1;
            }
            return r;
        }
        mint inv() const {
            if (prime) {
                assert(_v);
                return pow(umod() - 2);
            } else {
                auto eg = internal::inv_gcd(_v, m);
                assert(eg.first == 1);
                return eg.second;
            }
        }
        
        friend mint operator+(const mint& lhs, const mint& rhs) {
            return mint(lhs) += rhs;
        }
        friend mint operator-(const mint& lhs, const mint& rhs) {
            return mint(lhs) -= rhs;
        }
        friend mint operator*(const mint& lhs, const mint& rhs) {
            return mint(lhs) *= rhs;
        }
        friend mint operator/(const mint& lhs, const mint& rhs) {
            return mint(lhs) /= rhs;
        }
        friend bool operator==(const mint& lhs, const mint& rhs) {
            return lhs._v == rhs._v;
        }
        friend bool operator!=(const mint& lhs, const mint& rhs) {
            return lhs._v != rhs._v;
        }
        
    private:
        unsigned int _v;
        static constexpr unsigned int umod() { return m; }
        static constexpr bool prime = internal::is_prime<m>;
    };
    
    template <int id> struct dynamic_modint : internal::modint_base {
        using mint = dynamic_modint;
        
    public:
        static int mod() { return (int)(bt.umod()); }
        static void set_mod(int m) {
            assert(1 <= m);
            bt = internal::barrett(m);
        }
        static mint raw(int v) {
            mint x;
            x._v = v;
            return x;
        }
        
        dynamic_modint() : _v(0) {}
        template <class T, internal::is_signed_int_t<T>* = nullptr>
        dynamic_modint(T v) {
            long long x = (long long)(v % (long long)(mod()));
            if (x < 0) x += mod();
            _v = (unsigned int)(x);
        }
        template <class T, internal::is_unsigned_int_t<T>* = nullptr>
        dynamic_modint(T v) {
            _v = (unsigned int)(v % mod());
        }
        dynamic_modint(bool v) { _v = ((unsigned int)(v) % mod()); }
        
        unsigned int val() const { return _v; }
        
        mint& operator++() {
            _v++;
            if (_v == umod()) _v = 0;
            return *this;
        }
        mint& operator--() {
            if (_v == 0) _v = umod();
            _v--;
            return *this;
        }
        mint operator++(int) {
            mint result = *this;
            ++*this;
            return result;
        }
        mint operator--(int) {
            mint result = *this;
            --*this;
            return result;
        }
        
        mint& operator+=(const mint& rhs) {
            _v += rhs._v;
            if (_v >= umod()) _v -= umod();
            return *this;
        }
        mint& operator-=(const mint& rhs) {
            _v += mod() - rhs._v;
            if (_v >= umod()) _v -= umod();
            return *this;
        }
        mint& operator*=(const mint& rhs) {
            _v = bt.mul(_v, rhs._v);
            return *this;
        }
        mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }
        
        mint operator+() const { return *this; }
        mint operator-() const { return mint() - *this; }
        
        mint pow(long long n) const {
            assert(0 <= n);
            mint x = *this, r = 1;
            while (n) {
                if (n & 1) r *= x;
                x *= x;
                n >>= 1;
            }
            return r;
        }
        mint inv() const {
            auto eg = internal::inv_gcd(_v, mod());
            assert(eg.first == 1);
            return eg.second;
        }
        
        friend mint operator+(const mint& lhs, const mint& rhs) {
            return mint(lhs) += rhs;
        }
        friend mint operator-(const mint& lhs, const mint& rhs) {
            return mint(lhs) -= rhs;
        }
        friend mint operator*(const mint& lhs, const mint& rhs) {
            return mint(lhs) *= rhs;
        }
        friend mint operator/(const mint& lhs, const mint& rhs) {
            return mint(lhs) /= rhs;
        }
        friend bool operator==(const mint& lhs, const mint& rhs) {
            return lhs._v == rhs._v;
        }
        friend bool operator!=(const mint& lhs, const mint& rhs) {
            return lhs._v != rhs._v;
        }
        
    private:
        unsigned int _v;
        static internal::barrett bt;
        static unsigned int umod() { return bt.umod(); }
    };
    template <int id> internal::barrett dynamic_modint<id>::bt = 998244353;
    
    using modint998244353 = static_modint<998244353>;
    using modint1000000007 = static_modint<1000000007>;
    using modint = dynamic_modint<-1>;
    
    namespace internal {
        
        template <class T>
        using is_static_modint = std::is_base_of<internal::static_modint_base, T>;
        
        template <class T>
        using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;
        
        template <class> struct is_dynamic_modint : public std::false_type {};
        template <int id>
        struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};
        
        template <class T>
        using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;
        
    }  // namespace internal
    
}  // namespace atcoder

using mint=atcoder::modint1000000007;

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    while(1){
        int N;cin>>N;
        if(N==0) break;
        vector<int> x1(N),y1(N),x2(N),y2(N);
        for(int i=0;i<N;i++) cin>>x1[i]>>y1[i]>>x2[i]>>y2[i];
        
        vector<pair<int,int>> kou;
        for(int i=0;i<N;i++){
            for(int j=0;j<N;j++){
                {
                    int xi=x1[i],yi=y1[i],xj=x1[j],yj=y1[j];
                    int s=yj-yi,t=xi*yj-xj*yi;
                    if(t>0){
                        if(0<=s&&s<=t){
                            int g=gcd(s,t);
                            kou.push_back(mp(s/g,t/g));
                        }
                    }
                    if(t<0){
                        if(t<=s&&s<=0){
                            int g=gcd(abs(s),abs(t))*(-1);
                            kou.push_back(mp(s/g,t/g));
                        }
                    }
                }
                {
                    int xi=x1[i],yi=y1[i],xj=x2[j],yj=y2[j];
                    int s=yj-yi,t=xi*yj-xj*yi;
                    if(t>0){
                        if(0<=s&&s<=t){
                            int g=gcd(s,t);
                            kou.push_back(mp(s/g,t/g));
                        }
                    }
                    if(t<0){
                        if(t<=s&&s<=0){
                            int g=gcd(abs(s),abs(t))*(-1);
                            kou.push_back(mp(s/g,t/g));
                        }
                    }
                }
                {
                    int xi=x2[i],yi=y2[i],xj=x1[j],yj=y1[j];
                    int s=yj-yi,t=xi*yj-xj*yi;
                    if(t>0){
                        if(0<=s&&s<=t){
                            int g=gcd(s,t);
                            kou.push_back(mp(s/g,t/g));
                        }
                    }
                    if(t<0){
                        if(t<=s&&s<=0){
                            int g=gcd(abs(s),abs(t))*(-1);
                            kou.push_back(mp(s/g,t/g));
                        }
                    }
                }
                {
                    int xi=x2[i],yi=y2[i],xj=x2[j],yj=y2[j];
                    int s=yj-yi,t=xi*yj-xj*yi;
                    if(t>0){
                        if(0<=s&&s<=t){
                            int g=gcd(s,t);
                            kou.push_back(mp(s/g,t/g));
                        }
                    }
                    if(t<0){
                        if(t<=s&&s<=0){
                            int g=gcd(abs(s),abs(t))*(-1);
                            kou.push_back(mp(s/g,t/g));
                        }
                    }
                }
            }
        }
        
        for(int i=0;i<N;i++){
            kou.push_back(mp(1,x1[i]));
            kou.push_back(mp(1,x2[i]));
        }
        kou.push_back(mp(0,1));
        kou.push_back(mp(1,1));
        sort(all(kou));
        kou.erase(unique(all(kou)),kou.end());
        
        sort(all(kou),[](auto a,auto b){
            return a.fi*b.se<b.fi*a.se;
        });
        
        vector<mint> ans(N+1);
        
        for(int tt=0;tt+1<si(kou);tt++){
            pair<ll,ll> s=kou[tt],t=kou[tt+1];
            //cout<<s.fi<<" "<<s.se<<endl;
            vector<int> cn(N);
            int ok=0;
            vector<vector<pair<ll,ll>>> sousa;
            sousa.push_back({mp(0,1),mp(0,1),mp(-1,0)});
            sousa.push_back({mp(1,1),mp(1,1),mp(-1,0)});
            for(int i=0;i<N;i++){
                if(s.se-x1[i]*s.fi>0){
                    cn[i]++;
                    sousa.push_back({mp(s.se-x1[i]*s.fi,y1[i]*s.se),mp(t.se-x1[i]*t.fi,y1[i]*t.se),mp(i,1)});
                }
                if(s.se-x2[i]*s.fi>0){
                    cn[i]++;
                    sousa.push_back({mp(s.se-x2[i]*s.fi,y2[i]*s.se),mp(t.se-x2[i]*t.fi,y2[i]*t.se),mp(i,2)});
                }
                
                if(cn[i]%2==0) ok++;
            }
            //cout<<ok<<" ";
            for(int i=0;i<si(sousa);i++){
                for(int j=0;j<2;j++){
                    int a=sousa[i][j].fi,b=sousa[i][j].se;
                    int g=gcd(a,b);
                    sousa[i][j]=mp(a/g,b/g);
                }
            }
            sort(all(sousa),[](auto a,auto b){
                if(a[0].fi*b[0].se==b[0].fi*a[0].se){
                    return a[1].fi*b[1].se<b[1].fi*a[1].se;
                }
                return a[0].fi*b[0].se<b[0].fi*a[0].se;
            });
            mint asum=0,bsum=0;
            for(int i=0;i+1<si(sousa);i++){
                mint a=0,b=0,h=0;
                a=mint(sousa[i+1][0].fi)/mint(sousa[i+1][0].se)-mint(sousa[i][0].fi)/mint(sousa[i][0].se);
                b=mint(sousa[i+1][1].fi)/mint(sousa[i+1][1].se)-mint(sousa[i][1].fi)/mint(sousa[i][1].se);
                h=mint(t.fi)/mint(t.se)-mint(s.fi)/mint(s.se);
                ans[ok]+=(a+b)*h/mint(2);
                
                if(sousa[i+1][2].fi!=-1){
                    cn[sousa[i+1][2].fi]--;
                    if(cn[sousa[i+1][2].fi]&1) ok--;
                    else ok++;
                }
                
                assert(0<=ok&&ok<=N);
                asum+=a;
                bsum+=b;
            }
            
            //cout<<asum.val()<<" "<<bsum.val()<<endl;
            
            //cout<<ok<<endl;
        }
        
        for(int i=0;i<=N;i++){
            if(i) cout<<" ";
            cout<<ans[N-i].val();
        }
        cout<<endl;
    }
}
accuracy: 1
time_ms: 5200
memory_kb: 3584
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=105,INF=1<<30;

ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}

//modintのみ

// from: https://gist.github.com/yosupo06/ddd51afb727600fd95d9d8ad6c3c80c9
// (based on AtCoder STL)

#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {
    
    namespace internal {
        
#ifndef _MSC_VER
        template <class T>
        using is_signed_int128 =
        typename std::conditional<std::is_same<T, __int128_t>::value ||
        std::is_same<T, __int128>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_unsigned_int128 =
        typename std::conditional<std::is_same<T, __uint128_t>::value ||
        std::is_same<T, unsigned __int128>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using make_unsigned_int128 =
        typename std::conditional<std::is_same<T, __int128_t>::value,
        __uint128_t,
        unsigned __int128>;
        
        template <class T>
        using is_integral = typename std::conditional<std::is_integral<T>::value ||
        is_signed_int128<T>::value ||
        is_unsigned_int128<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                         std::is_signed<T>::value) ||
        is_signed_int128<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_unsigned_int =
        typename std::conditional<(is_integral<T>::value &&
                                   std::is_unsigned<T>::value) ||
        is_unsigned_int128<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using to_unsigned = typename std::conditional<
        is_signed_int128<T>::value,
        make_unsigned_int128<T>,
        typename std::conditional<std::is_signed<T>::value,
        std::make_unsigned<T>,
        std::common_type<T>>::type>::type;
        
#else
        
        template <class T> using is_integral = typename std::is_integral<T>;
        
        template <class T>
        using is_signed_int =
        typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_unsigned_int =
        typename std::conditional<is_integral<T>::value &&
        std::is_unsigned<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using to_unsigned = typename std::conditional<is_signed_int<T>::value,
        std::make_unsigned<T>,
        std::common_type<T>>::type;
        
#endif
        
        template <class T>
        using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;
        
        template <class T>
        using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;
        
        template <class T> using to_unsigned_t = typename to_unsigned<T>::type;
        
    }  // namespace internal
    
}  // namespace atcoder

#include <utility>

namespace atcoder {
    
    namespace internal {
        
        constexpr long long safe_mod(long long x, long long m) {
            x %= m;
            if (x < 0) x += m;
            return x;
        }
        
        struct barrett {
            unsigned int _m;
            unsigned long long im;
            
            barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}
            
            unsigned int umod() const { return _m; }
            
            unsigned int mul(unsigned int a, unsigned int b) const {
                
                unsigned long long z = a;
                z *= b;
#ifdef _MSC_VER
                unsigned long long x;
                _umul128(z, im, &x);
#else
                unsigned long long x =
                (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
                unsigned int v = (unsigned int)(z - x * _m);
                if (_m <= v) v += _m;
                return v;
            }
        };
        
        constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
            if (m == 1) return 0;
            unsigned int _m = (unsigned int)(m);
            unsigned long long r = 1;
            unsigned long long y = safe_mod(x, m);
            while (n) {
                if (n & 1) r = (r * y) % _m;
                y = (y * y) % _m;
                n >>= 1;
            }
            return r;
        }
        
        constexpr bool is_prime_constexpr(int n) {
            if (n <= 1) return false;
            if (n == 2 || n == 7 || n == 61) return true;
            if (n % 2 == 0) return false;
            long long d = n - 1;
            while (d % 2 == 0) d /= 2;
            for (long long a : {2, 7, 61}) {
                long long t = d;
                long long y = pow_mod_constexpr(a, t, n);
                while (t != n - 1 && y != 1 && y != n - 1) {
                    y = y * y % n;
                    t <<= 1;
                }
                if (y != n - 1 && t % 2 == 0) {
                    return false;
                }
            }
            return true;
        }
        template <int n> constexpr bool is_prime = is_prime_constexpr(n);
        
        constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
            a = safe_mod(a, b);
            if (a == 0) return {b, 0};
            
            long long s = b, t = a;
            long long m0 = 0, m1 = 1;
            
            while (t) {
                long long u = s / t;
                s -= t * u;
                m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b
                
                
                auto tmp = s;
                s = t;
                t = tmp;
                tmp = m0;
                m0 = m1;
                m1 = tmp;
            }
            if (m0 < 0) m0 += b / s;
            return {s, m0};
        }
        
        constexpr int primitive_root_constexpr(int m) {
            if (m == 2) return 1;
            if (m == 167772161) return 3;
            if (m == 469762049) return 3;
            if (m == 754974721) return 11;
            if (m == 998244353) return 3;
            int divs[20] = {};
            divs[0] = 2;
            int cnt = 1;
            int x = (m - 1) / 2;
            while (x % 2 == 0) x /= 2;
            for (int i = 3; (long long)(i)*i <= x; i += 2) {
                if (x % i == 0) {
                    divs[cnt++] = i;
                    while (x % i == 0) {
                        x /= i;
                    }
                }
            }
            if (x > 1) {
                divs[cnt++] = x;
            }
            for (int g = 2;; g++) {
                bool ok = true;
                for (int i = 0; i < cnt; i++) {
                    if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                        ok = false;
                        break;
                    }
                }
                if (ok) return g;
            }
        }
        template <int m> constexpr int primitive_root = primitive_root_constexpr(m);
        
    }  // namespace internal
    
}  // namespace atcoder

#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {
    
    namespace internal {
        
        struct modint_base {};
        struct static_modint_base : modint_base {};
        
        template <class T> using is_modint = std::is_base_of<modint_base, T>;
        template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;
        
    }  // namespace internal
    
    template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
    struct static_modint : internal::static_modint_base {
        using mint = static_modint;
        
    public:
        static constexpr int mod() { return m; }
        static mint raw(int v) {
            mint x;
            x._v = v;
            return x;
        }
        
        static_modint() : _v(0) {}
        template <class T, internal::is_signed_int_t<T>* = nullptr>
        static_modint(T v) {
            long long x = (long long)(v % (long long)(umod()));
            if (x < 0) x += umod();
            _v = (unsigned int)(x);
        }
        template <class T, internal::is_unsigned_int_t<T>* = nullptr>
        static_modint(T v) {
            _v = (unsigned int)(v % umod());
        }
        static_modint(bool v) { _v = ((unsigned int)(v) % umod()); }
        
        unsigned int val() const { return _v; }
        
        mint& operator++() {
            _v++;
            if (_v == umod()) _v = 0;
            return *this;
        }
        mint& operator--() {
            if (_v == 0) _v = umod();
            _v--;
            return *this;
        }
        mint operator++(int) {
            mint result = *this;
            ++*this;
            return result;
        }
        mint operator--(int) {
            mint result = *this;
            --*this;
            return result;
        }
        
        mint& operator+=(const mint& rhs) {
            _v += rhs._v;
            if (_v >= umod()) _v -= umod();
            return *this;
        }
        mint& operator-=(const mint& rhs) {
            _v -= rhs._v;
            if (_v >= umod()) _v += umod();
            return *this;
        }
        mint& operator*=(const mint& rhs) {
            unsigned long long z = _v;
            z *= rhs._v;
            _v = (unsigned int)(z % umod());
            return *this;
        }
        mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }
        
        mint operator+() const { return *this; }
        mint operator-() const { return mint() - *this; }
        
        mint pow(long long n) const {
            assert(0 <= n);
            mint x = *this, r = 1;
            while (n) {
                if (n & 1) r *= x;
                x *= x;
                n >>= 1;
            }
            return r;
        }
        mint inv() const {
            if (prime) {
                assert(_v);
                return pow(umod() - 2);
            } else {
                auto eg = internal::inv_gcd(_v, m);
                assert(eg.first == 1);
                return eg.second;
            }
        }
        
        friend mint operator+(const mint& lhs, const mint& rhs) {
            return mint(lhs) += rhs;
        }
        friend mint operator-(const mint& lhs, const mint& rhs) {
            return mint(lhs) -= rhs;
        }
        friend mint operator*(const mint& lhs, const mint& rhs) {
            return mint(lhs) *= rhs;
        }
        friend mint operator/(const mint& lhs, const mint& rhs) {
            return mint(lhs) /= rhs;
        }
        friend bool operator==(const mint& lhs, const mint& rhs) {
            return lhs._v == rhs._v;
        }
        friend bool operator!=(const mint& lhs, const mint& rhs) {
            return lhs._v != rhs._v;
        }
        
    private:
        unsigned int _v;
        static constexpr unsigned int umod() { return m; }
        static constexpr bool prime = internal::is_prime<m>;
    };
    
    template <int id> struct dynamic_modint : internal::modint_base {
        using mint = dynamic_modint;
        
    public:
        static int mod() { return (int)(bt.umod()); }
        static void set_mod(int m) {
            assert(1 <= m);
            bt = internal::barrett(m);
        }
        static mint raw(int v) {
            mint x;
            x._v = v;
            return x;
        }
        
        dynamic_modint() : _v(0) {}
        template <class T, internal::is_signed_int_t<T>* = nullptr>
        dynamic_modint(T v) {
            long long x = (long long)(v % (long long)(mod()));
            if (x < 0) x += mod();
            _v = (unsigned int)(x);
        }
        template <class T, internal::is_unsigned_int_t<T>* = nullptr>
        dynamic_modint(T v) {
            _v = (unsigned int)(v % mod());
        }
        dynamic_modint(bool v) { _v = ((unsigned int)(v) % mod()); }
        
        unsigned int val() const { return _v; }
        
        mint& operator++() {
            _v++;
            if (_v == umod()) _v = 0;
            return *this;
        }
        mint& operator--() {
            if (_v == 0) _v = umod();
            _v--;
            return *this;
        }
        mint operator++(int) {
            mint result = *this;
            ++*this;
            return result;
        }
        mint operator--(int) {
            mint result = *this;
            --*this;
            return result;
        }
        
        mint& operator+=(const mint& rhs) {
            _v += rhs._v;
            if (_v >= umod()) _v -= umod();
            return *this;
        }
        mint& operator-=(const mint& rhs) {
            _v += mod() - rhs._v;
            if (_v >= umod()) _v -= umod();
            return *this;
        }
        mint& operator*=(const mint& rhs) {
            _v = bt.mul(_v, rhs._v);
            return *this;
        }
        mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }
        
        mint operator+() const { return *this; }
        mint operator-() const { return mint() - *this; }
        
        mint pow(long long n) const {
            assert(0 <= n);
            mint x = *this, r = 1;
            while (n) {
                if (n & 1) r *= x;
                x *= x;
                n >>= 1;
            }
            return r;
        }
        mint inv() const {
            auto eg = internal::inv_gcd(_v, mod());
            assert(eg.first == 1);
            return eg.second;
        }
        
        friend mint operator+(const mint& lhs, const mint& rhs) {
            return mint(lhs) += rhs;
        }
        friend mint operator-(const mint& lhs, const mint& rhs) {
            return mint(lhs) -= rhs;
        }
        friend mint operator*(const mint& lhs, const mint& rhs) {
            return mint(lhs) *= rhs;
        }
        friend mint operator/(const mint& lhs, const mint& rhs) {
            return mint(lhs) /= rhs;
        }
        friend bool operator==(const mint& lhs, const mint& rhs) {
            return lhs._v == rhs._v;
        }
        friend bool operator!=(const mint& lhs, const mint& rhs) {
            return lhs._v != rhs._v;
        }
        
    private:
        unsigned int _v;
        static internal::barrett bt;
        static unsigned int umod() { return bt.umod(); }
    };
    template <int id> internal::barrett dynamic_modint<id>::bt = 998244353;
    
    using modint998244353 = static_modint<998244353>;
    using modint1000000007 = static_modint<1000000007>;
    using modint = dynamic_modint<-1>;
    
    namespace internal {
        
        template <class T>
        using is_static_modint = std::is_base_of<internal::static_modint_base, T>;
        
        template <class T>
        using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;
        
        template <class> struct is_dynamic_modint : public std::false_type {};
        template <int id>
        struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};
        
        template <class T>
        using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;
        
    }  // namespace internal
    
}  // namespace atcoder

using mint=atcoder::modint1000000007;

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    while(1){
        int N;cin>>N;
        if(N==0) break;
        vector<ll> x1(N),y1(N),x2(N),y2(N);
        for(int i=0;i<N;i++) cin>>x1[i]>>y1[i]>>x2[i]>>y2[i];
        
        vector<pair<ll,ll>> kou;
        for(int i=0;i<N;i++){
            for(int j=0;j<N;j++){
                {
                    ll xi=x1[i],yi=y1[i],xj=x1[j],yj=y1[j];
                    ll s=yj-yi,t=xi*yj-xj*yi;
                    if(t>0){
                        if(0<=s&&s<=t){
                            if(0<=t-s*xi&&t-s*xi<=t*yi){
                                ll g=gcd(s,t);
                                kou.push_back(mp(s/g,t/g));
                            }
                        }
                    }
                    if(t<0){
                        if(t<=s&&s<=0){
                            if(t*yi<=t-s*xi&&t-s*xi<=0){
                                ll g=gcd(abs(s),abs(t))*(-1);
                                kou.push_back(mp(s/g,t/g));
                            }
                        }
                    }
                }
                {
                    ll xi=x1[i],yi=y1[i],xj=x2[j],yj=y2[j];
                    ll s=yj-yi,t=xi*yj-xj*yi;
                    if(t>0){
                        if(0<=s&&s<=t){
                            if(0<=t-s*xi&&t-s*xi<=t*yi){
                                ll g=gcd(s,t);
                                kou.push_back(mp(s/g,t/g));
                            }
                        }
                    }
                    if(t<0){
                        if(t<=s&&s<=0){
                            if(t*yi<=t-s*xi&&t-s*xi<=0){
                                ll g=gcd(abs(s),abs(t))*(-1);
                                kou.push_back(mp(s/g,t/g));
                            }
                        }
                    }
                }
                {
                    ll xi=x2[i],yi=y2[i],xj=x1[j],yj=y1[j];
                    ll s=yj-yi,t=xi*yj-xj*yi;
                    if(t>0){
                        if(0<=s&&s<=t){
                            if(0<=t-s*xi&&t-s*xi<=t*yi){
                                ll g=gcd(s,t);
                                kou.push_back(mp(s/g,t/g));
                            }
                        }
                    }
                    if(t<0){
                        if(t<=s&&s<=0){
                            if(t*yi<=t-s*xi&&t-s*xi<=0){
                                ll g=gcd(abs(s),abs(t))*(-1);
                                kou.push_back(mp(s/g,t/g));
                            }
                        }
                    }
                }
                {
                    ll xi=x2[i],yi=y2[i],xj=x2[j],yj=y2[j];
                    ll s=yj-yi,t=xi*yj-xj*yi;
                    if(t>0){
                        if(0<=s&&s<=t){
                            if(0<=t-s*xi&&t-s*xi<=t*yi){
                                ll g=gcd(s,t);
                                kou.push_back(mp(s/g,t/g));
                            }
                        }
                    }
                    if(t<0){
                        if(t<=s&&s<=0){
                            if(t*yi<=t-s*xi&&t-s*xi<=0){
                                ll g=gcd(abs(s),abs(t))*(-1);
                                kou.push_back(mp(s/g,t/g));
                            }
                        }
                    }
                }
            }
        }
        
        for(int i=0;i<N;i++){
            kou.push_back(mp(1,x1[i]));
            kou.push_back(mp(1,x2[i]));
        }
        kou.push_back(mp(0,1));
        kou.push_back(mp(1,1));
        sort(all(kou));
        kou.erase(unique(all(kou)),kou.end());
        
        sort(all(kou),[](auto a,auto b){
            return a.fi*b.se<b.fi*a.se;
        });
        
        vector<mint> ans(N+1);
        
        for(int tt=0;tt+1<si(kou);tt++){
            pair<ll,ll> s=kou[tt],t=kou[tt+1];
            //cout<<s.fi<<" "<<s.se<<endl;
            vector<int> cn(N);
            int ok=0;
            vector<vector<pair<ll,ll>>> sousa;
            sousa.push_back({mp(0,1),mp(0,1),mp(-1,0)});
            sousa.push_back({mp(1,1),mp(1,1),mp(-1,0)});
            for(int i=0;i<N;i++){
                if(s.se-x1[i]*s.fi>0){
                    cn[i]++;
                    sousa.push_back({mp(s.se-x1[i]*s.fi,y1[i]*s.se),mp(t.se-x1[i]*t.fi,y1[i]*t.se),mp(i,1)});
                }
                if(s.se-x2[i]*s.fi>0){
                    cn[i]++;
                    sousa.push_back({mp(s.se-x2[i]*s.fi,y2[i]*s.se),mp(t.se-x2[i]*t.fi,y2[i]*t.se),mp(i,2)});
                }
                
                if(cn[i]%2==0) ok++;
            }
            //cout<<ok<<" ";
            for(int i=0;i<si(sousa);i++){
                for(int j=0;j<2;j++){
                    ll a=sousa[i][j].fi,b=sousa[i][j].se;
                    ll g=gcd(a,b);
                    sousa[i][j]=mp(a/g,b/g);
                }
            }
            sort(all(sousa),[](auto a,auto b){
                if(a[0].fi*b[0].se==b[0].fi*a[0].se){
                    return a[1].fi*b[1].se<b[1].fi*a[1].se;
                }
                return a[0].fi*b[0].se<b[0].fi*a[0].se;
            });
            mint asum=0,bsum=0;
            for(int i=0;i+1<si(sousa);i++){
                mint a=0,b=0,h=0;
                a=mint(sousa[i+1][0].fi)/mint(sousa[i+1][0].se)-mint(sousa[i][0].fi)/mint(sousa[i][0].se);
                b=mint(sousa[i+1][1].fi)/mint(sousa[i+1][1].se)-mint(sousa[i][1].fi)/mint(sousa[i][1].se);
                h=mint(t.fi)/mint(t.se)-mint(s.fi)/mint(s.se);
                ans[ok]+=(a+b)*h/mint(2);
                
                if(sousa[i+1][2].fi!=-1){
                    cn[sousa[i+1][2].fi]--;
                    if(cn[sousa[i+1][2].fi]&1) ok--;
                    else ok++;
                }
                
                assert(0<=ok&&ok<=N);
                asum+=a;
                bsum+=b;
            }
            
            //cout<<asum.val()<<" "<<bsum.val()<<endl;
            
            //cout<<ok<<endl;
        }
        
        for(int i=0;i<=N;i++){
            if(i) cout<<" ";
            cout<<ans[N-i].val();
        }
        cout<<endl;
    }
}
accuracy: 1
time_ms: 4760
memory_kb: 3624
final_rank: 5

code_snippet: //#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 20;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

ll gcd(ll x, ll y) {
	x = abs(x), y = abs(y);
	if (x < y)swap(x, y);
	while (y) {
		ll r = x % y; x = y; y = r;
	}
	return x;
}

//0/0だけ気を付けて！
struct ratio {
	ll a, b;
	ratio(ll x) { a = x; b = 1; };
	ratio(ll x, ll y) {
		a = x; b = y;
		ll g = gcd(x, y);
		if (g > 0) {
			a /= g, b /= g;
			if (b < 0)a = -a, b = -b;
		}
	};

};

void normalize(ratio& r) {
	ll g = gcd(r.a, r.b);
	r.a /= g; r.b /= g;
	if (r.b < 0)r.b = -r.b, r.a = -r.a;
}
bool operator<(const ratio& x, const ratio& y) {
	return x.a * y.b < x.b* y.a;
}
bool operator==(const ratio& x, const ratio& y) {
	return x.a * y.b == x.b * y.a;
}
bool operator<=(const ratio& x, const ratio& y) {
	return x < y || x == y;
}
ratio operator-(const ratio& x, const ratio& y) {
	ll g = gcd(x.b, y.b);
	ll a = x.a * (y.b / g) - y.a * (x.b / g);
	ll b = (x.b / g) * y.b;
	return ratio(a, b);
}
ratio operator+(const ratio& x, const ratio& y) {
	ll g = gcd(x.b, y.b);
	ll a = x.a * (y.b / g) + y.a * (x.b / g);
	ll b = (x.b / g) * y.b;
	return ratio(a, b);
}
ratio operator-=(ratio& x, const ratio& y) {
	x = x - y; return x;
}
ratio operator*(const ratio& x, const ratio& y) {
	ll g = gcd(x.b, y.a);
	ll a1 = y.a / g;
	ll b1 = x.b / g;
	g = gcd(x.a, y.b);
	ll a2 = x.a / g;
	ll b2 = y.b / g;
	return ratio(a1 * a2, b1 * b2);
}
ratio inv(const ratio& x) {
	return ratio(x.b, x.a);
}

int n;
void solve() {
	vector<int> x1(n), y1(n), x2(n), y2(n);
	rep(i, n) {
		cin >> x1[i] >> y1[i] >> x2[i] >> y2[i];
	}
	vector<ratio> vr;
	rep(i, n) {
		ratio r1(1, x1[i]);
		ratio r2(1, x2[i]);
		vr.push_back(r1);
		vr.push_back(r2);
	}
	vector<P> vp;
	rep(i, n) {
		vp.push_back({ x1[i],y1[i] });
		vp.push_back({ x2[i],y2[i] });
	}
	auto calc = [&](ratio x, ratio y, ratio cx) {
		x = inv(x); y = inv(y);
		ratio res(1, 1);
		res -= cx * x;
		res = res * inv(y);
		return res;
	};
	auto trans = [&](ratio& x) {
		if (x.a < 0)x = ratio(0, 1);
		if (x.a >= x.b)x = ratio(1, 1);
	};
	auto tomodint = [&](ratio x) {
		modint res = x.a;
		if (x.b < max_n)res *= fact[x.b - 1] * factinv[x.b];
		else res /= x.b;
		return res;
	};
	rep(i, vp.size())Rep(j, i + 1, vp.size()) {
		int x1 = vp[i].first;
		int y1 = vp[i].second;
		int x2 = vp[j].first;
		int y2 = vp[j].second;
		if (x1 * y2 == x2 * y1)continue;
		int a = y2 - y1;
		int b = x1 * y2 - x2 * y1;
		if (b < 0) {
			a = -a;
			b = -b;
		}
		if (a <= 0 || a >= b)continue;
		vr.push_back(ratio(a, b));
	}
	vr.push_back(ratio(0, 1));
	vr.push_back(ratio(1, 1));
	sort(all(vr));
	vr.erase(unique(all(vr)), vr.end());
	vector<modint> ans(n + 1);
	rep(i, vr.size() - 1) {
		//cout << "! " << vr[i].a << " " << vr[i].b << "\n";
		modint dx = 0;
		dx += tomodint(vr[i + 1]);
		dx -= tomodint(vr[i]);
		using Pr = pair<ratio, ratio>;
		vector<pair<Pr, int>> v;
		rep(j, n) {
			rep(k, 2) {
				ratio x = ratio(1, x1[j]);
				ratio y = ratio(1, y1[j]);
				if (k == 1) {
					x = ratio(1, x2[j]);
					y = ratio(1, y2[j]);
				}
				ratio r1 = calc(x, y, vr[i]);
				ratio r2 = calc(x, y, vr[i + 1]);
				if (i == 1) {
					//cout << "? " << r1.a << " " << r1.b << " " << r2.a << " " << r2.b << "\n";
				}
				v.push_back({ {r1,r2},j });
			}
		}
		v.push_back({ {ratio(-mod,1),ratio(-mod,1)},-1 });
		v.push_back({ {ratio(2,1),ratio(2,1)},-1 });
		sort(all(v));
		vector<int> tmp(n);
		int cur = 0;
		rep(j, v.size() - 1) {
			int id = v[j].second;
			if (id >= 0) {
				if (tmp[id] == 0)cur++;
				else cur--;
				tmp[id]++;
			}
			ratio l1 = v[j].first.first;
			ratio l2 = v[j].first.second;
			ratio r1 = v[j + 1].first.first;
			ratio r2 = v[j + 1].first.second;
			trans(l1); trans(l2); trans(r1); trans(r2);
			modint dy = 0;
			dy += tomodint(r1);
			dy -= tomodint(l1);
			dy += tomodint(r2);
			dy -= tomodint(l2);
			//cout << "? " << dx <<" "<<dy<< " "<<cur<<"\n";
			ans[cur] += dx * dy / (modint)2;
		}
	}
	rep(i, n + 1) {
		if (i > 0)cout << " ";
		cout << ans[i];
	}
	cout << "\n";
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(8);
	init_f();
	//init();
	//int t; cin >> t; rep(i, t)
	while (cin >> n, n)
		solve();
	return 0;
}
accuracy: 1
time_ms: 7870
memory_kb: 19900
final_rank: 11

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <cstdio>
#include <tuple>
#include <cassert>
#include <climits>
#include <cstdlib>
using namespace std;

#define ALL(v) begin(v),end(v)
#define REP(i,n) for(int i=0;i<int(n);++i)

using LL = long long;
const LL MOD = 1000000007;

LL mul(LL x, LL y){
	assert(y == 0 || abs(x) <= LLONG_MAX / abs(y));
	return x * y;
}

LL gcd(LL x, LL y){
	while(y){
		LL r = x % y;
		x = y;
		y = r;
	}
	return x;
}

LL inv(LL x){
	LL y = MOD - 2;
	LL a = 1;
	x %= MOD;
	while(y){
		if(y & 1){ a = a * x % MOD; }
		x = x * x % MOD;
		y >>= 1;
	}
	return a;
}

struct R{
	LL a, b;
	R(LL x = 0){ a = x; b = 1; }
	R(LL x, LL y){
		LL d = gcd(x, y);
		if((d < 0) != (y < 0)){ d = -d; }
		a = x / d;
		b = y / d;
	}
	bool operator== (const R &r) const{
		return a == r.a && b == r.b;
	}
#if 0
	static bool lt(LL a, LL b, LL c, LL d){
		if(a / b != c / d){ return a / b < c / d; }
		if(b == d){ return a < c; }
		a %= b;
		c %= d;
		if(a == 0){ return true; }
		if(c == 0){ return false; }
		return !lt(b, a, d, c);
	}
	bool operator< (const R &r) const{
		if(*this == r){ return false; }
		if((a > 0) != (r.a > 0)){ return a < r.a; }
		if(a < 0){ return !lt(-a, b, -r.a, r.b); }
		return lt(a, b, r.a, r.b);
	}
#else
	bool operator< (const R &r) const{
		return mul(a, r.b) < mul(b, r.a);
	}
#endif
	R operator+ (const R &r) const{
		return R(mul(a, r.b) + mul(b, r.a), mul(b, r.b));
	}
	R operator- (const R &r) const{
		return R(mul(a, r.b) - mul(b, r.a), mul(b, r.b));
	}
	R operator* (const R &r) const{
		return R(mul(a, r.a), mul(b, r.b));
	}
	R operator/ (const R &r) const{
		return R(mul(a, r.b), mul(b, r.a));
	}
	LL mod() const{
		return a % MOD * inv(b) % MOD;
	}
};
ostream &operator<< (ostream &os, const R &r){
	return os << "(" << r.a << "/" << r.b << ")";
}

void solve(int n){
	vector<R> as, bs;
	REP(i, n){
		LL x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		as.emplace_back(1, x1);
		bs.emplace_back(1, y1);
		as.emplace_back(1, x2);
		bs.emplace_back(1, y2);
	}

	vector<R> eas = as;
	vector<pair<R,int>> ebs;
	REP(i, 2 * n)
	REP(j, i){
		if(as[i] == as[j] || bs[i] == bs[j]){ continue; }
		if((as[i] < as[j]) == (bs[i] < bs[j])){ continue; }
		eas.push_back((bs[j] - bs[i]) / (bs[j] / as[j] - bs[i] / as[i]));
	}
	eas.emplace_back(1);
	sort(ALL(eas));

	R zero(0);
	R one(1);
	R two(2);
	R l = zero;
	vector<LL> ans(n + 1);
	for(const R &r : eas){
		LL dx = r.mod() - l.mod();
		R c = (l + r) / two;
		ebs.clear();
		ebs.emplace_back(one, 0);
		auto gety = [&](int j){
			if(c < as[j]){ return bs[j] * (one - c / as[j]); }
			return zero;
		};
		REP(i, n){
			R y1, y2;
			tie(y1, y2) = minmax(gety(i * 2), gety(i * 2 + 1));
			ebs.emplace_back(y1, 1);
			ebs.emplace_back(y2, -1);
		}
		sort(ALL(ebs));

		LL py = 0;
		int cnt = 0;
		for(const auto &p : ebs){
			LL y = p.first.mod();
			if(y != py){
				ans[cnt] = (ans[cnt] + (y - py) * dx) % MOD;
				py = y;
			}
			cnt += p.second;
		}
		l = r;
	}
	const char *spl = "";
	for(LL z : ans){
		z = (z % MOD + MOD) % MOD;
		cout << spl << z;
		spl = " ";
	}
	cout << "\n";
}

int main(){
	int n;
	while(cin >> n && n){
		solve(n);
	}
}
accuracy: 1
time_ms: 6300
memory_kb: 3644
final_rank: 8

code_snippet: #include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
#define _GLIBCXX_DEBUG
using namespace std;
using std::cout;
using std::cin;
using std::endl;
using ll=long long;
using ld=long double;
ll ILL=1167167167167167167;
const int INF=2100000000;
const ll mod=1e9+7;
const ll half=5e8+4;
#define rep(i,a) for (ll i=0;i<a;i++)
template<class T> using _pq = priority_queue<T, vector<T>, greater<T>>;
template<class T> ll LB(vector<T> &v,T a){return lower_bound(v.begin(),v.end(),a)-v.begin();}
template<class T> ll UB(vector<T> &v,T a){return upper_bound(v.begin(),v.end(),a)-v.begin();}
template<class T> bool chmin(T &a,const T &b){if(a>b){a=b;return 1;}else return 0;}
template<class T> bool chmax(T &a,const T &b){if(a<b){a=b;return 1;}else return 0;}
template<class T> void So(vector<T> &v) {sort(v.begin(),v.end());}
template<class T> void Sore(vector<T> &v) {sort(v.begin(),v.end(),[](T x,T y){return x>y;});}
void yneos(bool a){if(a) cout<<"Yes\n"; else cout<<"No\n";}

ll my_pow(ll a,ll b){
	if(b==0) return 1;
	if(b&1) return (a*my_pow(a,b^1))%mod;
	return my_pow((a*a)%mod,b>>1);
}

ll gcd(ll a,ll b){
	if(b==0) return a;
	return gcd(b,a%b);
}

void solve(int n);

pair<ll,ll> div(pair<ll,ll> &a,ll &b){
	return {a.first,a.second*b};
}
pair<ll,ll> one(pair<ll,ll> &a){
	return {a.second-a.first,a.second};
}
pair<ll,ll> diff(pair<ll,ll> &a,pair<ll,ll> &b){
	return {a.second*b.first-a.first*b.second,a.second*b.second};
}
pair<ll,ll> mul(pair<ll,ll> &a,pair<ll,ll> b){
	return {a.first*b.first,a.second*b.second};
}
ll f(pair<ll,ll> a){
	return (a.first*my_pow(a.second%mod,mod-2))%mod;
}
bool left_small(pair<ll,ll> &l,pair<ll,ll> &r){
	return l.first*r.second<l.second*r.first;
}
bool same(pair<ll,ll> &l,pair<ll,ll> &r){
	return l.first*r.second==l.second*r.first;
}
pair<ll,ll> zero(pair<ll,ll> &a){
	return {max(0ll,a.first),a.second};
}

pair<ll,ll> right(pair<ll,ll> &a){
	ll tmp=gcd(a.first,a.second);
	return {a.first/tmp,a.second/tmp};
}

pair<ll,ll> g(pair<ll,ll> tmp,ll X,ll Y){
	tmp=mul(tmp,{Y,1});
	tmp=one(tmp);
	tmp=zero(tmp);
	tmp=div(tmp,X);
	return right(tmp);
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int N;
	while(cin>>N,N){
		solve(N);
	}
}

void solve(int n){
	vector<ll> x(n*2),y(n*2),x2(n),y2(n);
	rep(i,n*2){
		cin>>x[i]>>y[i];
	}
	vector<ll> ans(n+1);
	vector<pair<ll,ll>> p={{0,1}};
	rep(i,100){
		p.push_back({1,i+1});
	}
	rep(i,n*2) rep(j,i){
		if(x[i]!=x[j]&&((x[j]-x[i])*(y[i]*x[j]-x[i]*y[j]))>0&&abs(x[j]-x[i])<abs(y[i]*x[j]-x[i]*y[j])){
			p.push_back({abs(x[i]-x[j]),abs(y[i]*x[j]-x[i]*y[j])});
		}
	}
	rep(i,p.size()) p[i]=right(p[i]);
	sort(p.begin(),p.end(),[&](pair<ll,ll> l,pair<ll,ll> r){
		return left_small(l,r);
	});
	vector<vector<pair<ll,ll>>> all_q(p.size(),vector<pair<ll,ll>>(n*2));
	vector<vector<ll>> all_f(p.size(),vector<ll>(n*2));
	rep(i,p.size()) rep(j,n*2){
		all_q[i][j]=g(p[i],x[j],y[j]);
		all_f[i][j]=f(all_q[i][j]);
	}
	rep(i,p.size()-1){
		vector<int> q(2*n);
		rep(j,n*2) q[j]=j;
		sort(q.begin(),q.end(),[&](int l,int r){
			if(same(all_q[i][l],all_q[i][r])) return left_small(all_q[i+1][l],all_q[i+1][r]);
			return left_small(all_q[i][l],all_q[i][r]);
		});
		ll D=(f(diff(p[i],p[i+1]))*half)%mod;
		int C=0;
		vector<int> r(n);
		rep(j,2*n-1){
			r[q[j]/2]^=1;
			C+=2*r[q[j]/2]-1;
			ll tmp=-(all_f[i][q[j]]+all_f[i+1][q[j]]);
			tmp+=(all_f[i][q[j+1]]+all_f[i+1][q[j+1]]);
			tmp%=mod;
			tmp*=D;
			tmp%=mod;
			ans[C]=(ans[C]+tmp)%mod;
		}
	}
	ans[0]=1;
	rep(i,n){
		ans[i+1]=(ans[i+1]+mod)%mod;
		ans[0]-=ans[i+1];
		ans[0]%=mod;
	}
	ans[0]=(ans[0]+mod)%mod;
	rep(i,n+1){
		if(i) cout<<" ";
		cout<<ans[i];
	}
	cout<<"\n";
}
accuracy: 1
time_ms: 3850
memory_kb: 15344
final_rank: 10