Problem: Dr. Asimov, a robotics researcher, has succeeded in developing a new robot. The robot can move freely along a special wire stretched around the floor. The robot always moves forward in a direction parallel to the current wire.

The good news is that this robot doesn't consume energy to move on the wire, regardless of its distance. However, in order to change the direction at the end point of the wire or the intersection of the wires, it is necessary to rotate around that point, and energy is consumed by the rotation angle.

I want to move this robot from the start point to the goal point. For example, in the figure below, place the robot at start in the east direction (the positive direction of the x-axis in the figure below) and move it to the goal. There is a route from start to the goal via intersection A and intersection B, and a route via intersection A and intersection C, but the former has a longer travel distance but a smaller rotation angle, so it consumes less energy.


<image>


Your job is to create a program that reads the position of the wires on the floor, the start point, the goal point, and reports the minimum total rotation angle required to move from the start point to the goal point.

The robot may be placed in any direction at the start point and in any direction at the goal point.



Input

The input consists of multiple datasets. The format of each dataset is as follows:


n
x11 y11 x21 y21
x12 y12 x22 y22
..
..
..
x1n y1n x2n y2n
sx sy gx gy


n is an integer indicating the number of wires. x1i y1i shows the coordinates of one end point of the i-th wire, and x2i y2i shows the coordinates of the other end point of the i-th wire.

sx sy and gx gy indicate the coordinates of the start point and the goal point, respectively.

All given coordinates are integer values, and the x-axis and y-axis values ​​are -1000 or more and 1000 or less. It may also be assumed that the start and finish points are on the end points of the given wire.

You can assume that n ≤ 50.

When n is 0, it indicates the end of input.

Output

For each dataset, output the minimum value of the total rotation angle on one line. If the robot cannot reach the goal point, output "-1". The output may contain an error of 0.00001 or less.

Example

Input

8
1 3 11 3
5 3 13 11
10 10 17 10
11 2 11 6
10 5 14 5
13 6 13 2
17 10 17 3
13 3 19 3
1 3 19 3
6
1 3 11 3
5 3 13 11
10 10 17 10
11 2 11 6
10 5 14 5
13 3 19 3
1 3 19 3
2
0 0 7 0
3 0 7 3
0 0 7 3
0


Output

270.0000
-1
36.86989765

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)
using namespace std;
typedef long long LL;

typedef complex<double> P;
const double EPS = 1e-8;

// 誤差を加味した符号判定
int sign(double x){ return x > EPS ? 1 : x < -EPS ? -1 : 0; }

// 内積・外積
double dot(P a, P b){return real(conj(a) * b);}
double cross(P a, P b){return imag(conj(a) * b);}

// OAとOBのなす符号付き角度 [-pi, pi]
// example : (1, 0), (0, 1) -> pi/2
double angle(P a, P b){return arg(conj(a) * b);}

// aをc中心にb[rad]回転
P rotate(P a, double b, P c = P()){return (a - c) * polar(1.0, b) + c;}

int ccw(P a, P b, P c) {
    b -= a; c -= a;
    if (cross(b, c) > +EPS)   return +1; // 反時計回り
    if (cross(b, c) < -EPS)   return -1; // 時計回り
    if (dot(b, c) < -EPS)     return +2; // c--a--b の順番で一直線上
    if (norm(b) + EPS < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}

enum{ OUT, ON, IN };

// Pointの比較をしたいときだけ定義する．
namespace std{
    bool operator < (const P& a, const P& b) {
        return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
    }
};

typedef vector<P> L;
P vec(L l){return l[1] - l[0];}

// 線分と点の交差判定(端点の処理に注意)(端点は含むけれども誤差に注意)
// verify : AOJ1279, AOJ2506
bool iSP(L s, P p) {return ccw(s[0], s[1], p) == 0;}

// 直線と直線の交点
// Verified: AOJ2579
// size()によって場合分け
// *4 : 直線が重なる  *1 : 交点が1つ存在 *0 : 直線が交差しない
vector<P> pLL(L l, L m){
    double A = cross(vec(l), vec(m));
    double B = cross(vec(l), l[1] - m[0]);
    if(sign(A) == 0 && sign(B) == 0) return {l[0], l[1], m[0], m[1]}; // 二直線が重なっている
    if(sign(A) == 0) return{}; // 直線が交わらない
    return {m[0] + vec(m) * B / A};
}

vector<P> pSS(L l, L m){
    vector<P> res;
    auto find = [&](P p){ 
        for(P r : res) if(sign(abs(r - p)) == 0)
                return true;
        return false;
    };
    for(P p : pLL(l, m))
        if(iSP(l,p) && iSP(m,p) && !find(p)) // 片方が直線の場合は適宜変えること
            res.push_back(p);
    return res;
}

// 入力
// ss : 線分のリスト
//
// 出力
// ps : グラフの頂点番号に対応する点が入る
// 返り値 : 上の説明のグラフ
//
// Verified
// AOJ 2113
typedef vector<int> Node;
typedef vector<Node> Graph;
Graph segment_arrangement(const vector<L> &ss, vector<P> &ps) {
    for (int i = 0; i < ss.size(); i++) {
        ps.push_back( ss[i][0] );
        ps.push_back( ss[i][1] );
        for (int j = i+1; j < ss.size(); j++){
            auto cp = pSS(ss[i], ss[j]);
            if (!cp.empty()) {
                assert(cp.size() == 1);
                ps.push_back( cp.back() );
            }
        }
    }
    sort(ps.begin(), ps.end());
    ps.erase(unique(ps.begin(), ps.end()), ps.end());

    Graph g(ps.size());
    for (int i = 0; i < ss.size(); i++) {
        vector<int> on;
        for (int j = 0; j < ps.size(); j++){
            if (iSP(ss[i], ps[j])){
                on.push_back(j);
            }
        }
        for (int j = 0; j + 1 < on.size(); j++) {
            for(int k = j + 1; k < on.size(); k++) {
                int a = on[j], b = on[k];
                g[a].push_back( b );
                g[b].push_back( a );
            }
        }
    }
    return g;
}

// 線分併合
//
// 線分のリストからオーバーラップするものたちをまとめ,新しい線分のリストを作る.
// 元々の線分のリストにおける順番は破壊される．
//
// not verified
void merge_segments(vector<L>& segs) {
    auto merge_if_able = [](L& s, L t){
        if (abs(cross(s[1]-s[0], t[1]-t[0])) > EPS) return false;
        //if (sign(cross(vec(s), vec(t))) != 0) return false;
        if (ccw(s[0], t[0], s[1]) == +1 ||
                ccw(s[0], t[0], s[1]) == -1) return false; // not on the same line
        if (ccw(s[0], s[1], t[0]) == -2 ||
                ccw(t[0], t[1], s[0]) == -2) return false; // separated
        s = { min(s[0], t[0]), max(s[1], t[1]) };
        return true;
    };
    for (int i = 0; i < segs.size(); ++i)
        if (segs[i][1] < segs[i][0])
            swap(segs[i][1], segs[i][0]);
    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();
}
P input() {
    double x, y;
    cin >> x >> y;
    return {x, y};
}
typedef tuple<double, int, int> T;
const int MAX = 500;
const double INF = 1e64;

int main(){
    int n;
    while(cin >> n && n > 0){
        vector<L> lines(n);
        REP(i, n) {
            P a = input();
            P b = input();
            lines[i] = {a, b};
        }

        merge_segments(lines);
        //assert(size == lines.size());

        vector<P> ps;
        Graph G = segment_arrangement(lines, ps);
        /*
        REP(i, G.size()){
            cout << i << ":";
            for(int v : G[i]) cout << v << " ";
            cout << endl;
        }
        */
        assert(ps.size() < MAX);

        REP(i, ps.size()) REP(j, i) {
            assert(abs(ps[i] - ps[j]) > EPS);
        }

        auto find = [](const vector<P>& pv, P p) -> int {
            for(int i = 0; i < pv.size(); i++) {
                auto q = pv[i];
                if(abs(p - q) < EPS) {
                    return i;
                }
            }
            return -1;
        };
        
        P sp = input();
        P gp = input();
        int s = find(ps, sp);
        int g = find(ps, gp);

        if(s == g) {
            cout << 0 << endl;
            continue;
        }

        assert(s != -1 && g != -1);

        priority_queue<T, vector<T>, greater<T>> que;
        double dist[MAX][MAX] = {};
        REP(i, MAX) REP(j, MAX) dist[i][j] = INF;
        for(int u : G[s]) {
            dist[s][u] = 0.0;
            que.push(T(0.0, s, u));
        }
        double ans = INF;
        while(!que.empty()) {
            T t = que.top(); que.pop();
            double d;
            int u, v;
            tie(d, u, v) = t;
            if(v == g) {
                ans = d;
                break;
            }
            for(int w : G[v]) if(u != w) {
                P p = ps[v] - ps[u];
                P q = ps[w] - ps[v];
                double th = abs(angle(p, q)) / M_PI * 180.0;
                double nd = d + th;
                if(dist[v][w] > nd) {
                    dist[v][w] = nd;
                    que.push(T(nd, v, w));
                }
            }
        }
        if(ans == INF) {
            cout << -1 << endl;
        } else {
            printf("%.12f\n", ans);
        }
    }

    return 0;
}