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>

using namespace std;

#define int long long
#define FR first
#define SC second
#define all(v) (v).begin(), (v).end()
#define rep(i, n) for(int i = 0; i < (int)(n); i++)
#define reps(i, f, n) for(int i = (int)(f); i < (int)(n); i++)
#define each(a, b) for(auto& a : b)

typedef pair<int, int> P;

const int inf = 1LL << 55;

#define EPS (1e-10)
#define equals(a, b) (fabs((a)-(b)) < EPS)
#define lt(a, b) ((a) - (b) < -EPS)

// ???/????????????
struct Point {
  double x, y;
  Point(double x = 0.0, double y = 0.0):x(x), y(y){}
  
  Point operator + (Point p) { return Point(x + p.x, y + p.y); }
  Point operator - (Point p) { return Point(x - p.x, y - p.y); }
  Point operator * (double a) { return Point(x * a, y * a); }
  Point operator / (double a) { return Point(x / a, y / a); }

  double abs() { return sqrt(norm()); }
  double norm() { return x*x + y*y; }

  bool operator < (const Point& p) const {
    return x != p.x ? x < p.x : y < p.y;
  }
  bool operator == (const Point& p) const {
    return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
  }
};
typedef Point Vector;

// ???
struct Circle {
  Point c;
  double r;
  Circle(Point c = Point(), double r = 0.0):c(c), r(r){}
};

// ????§???¢
typedef vector<Point> Polygon;

// ??????/??´???
struct Segment {
  Point p1, p2;
  Segment(Point p1 = Point(), Point p2 = Point()):p1(p1), p2(p2){}
};
typedef Segment Line;

// ????????????????????????
double norm(Vector v)
{
  return v.x*v.x + v.y*v.y;
}
// ?????????????????§??????
double abs(Vector v)
{
  return sqrt(norm(v));
}
// ?????????????????????
double dot(Vector a, Vector b)
{
  return a.x*b.x + a.y*b.y;
}
// ??????????????????????????§??????
double cross(Vector a, Vector b)
{
  return a.x*b.y - a.y*b.x;
}
// ??´?????????
bool isOrthogonal(Vector a, Vector b)
{
  return equals(dot(a, b), 0.0);
}
bool isOrthogonal(Point a1, Point a2, Point b1, Point b2)
{
  return isOrthogonal(a1 - a2, b1 - b2);
}
bool isOrthogonal(Segment s1, Segment s2)
{
  return equals(dot(s1.p2 - s1.p1, s2.p2 - s2.p1), 0.0);
}
// ????????????
bool isParallel(Vector a, Vector b)
{
  return equals(cross(a, b), 0.0);
}
bool isParallel(Point a1, Point a2, Point b1, Point b2)
{
  return isParallel(a1 - a2, b1 - b2);
}
bool isParallel(Segment s1, Segment s2)
{
  return equals(cross(s1.p2 - s1.p1, s2.p2 - s2.p1), 0.0);
}
// ?°???±
Point project(Segment s, Point p)
{
  Vector base = s.p2 - s.p1;
  double r = dot(p - s.p1, base) / norm(base);
  return s.p1 + base * r;
}
// ????°?
Point reflect(Segment s, Point p)
{
  return p + (project(s, p) - p) * 2.0;
}
static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE         = -1;
static const int ONLINE_BACK       = 2;
static const int ONLINE_FRONT      = -2;
static const int ON_SEGMENT        = 0;
// ???????¨???????
int ccw(Point p0, Point p1, Point p2)
{
  Vector a = p1 - p0;
  Vector b = p2 - p0;
  if(cross(a, b) > EPS) return COUNTER_CLOCKWISE;
  if(cross(a, b) < -EPS) return CLOCKWISE;
  if(dot(a, b) < -EPS) return ONLINE_BACK;
  if(a.norm() < b.norm()) return ONLINE_FRONT;
  return ON_SEGMENT;
}
// ????????????
bool intersect(Point p1, Point p2, Point p3, Point p4)
{
  return (ccw(p1, p2, p3) * ccw(p1, p2, p4) <= 0 &&
	  ccw(p3, p4, p1) * ccw(p3, p4, p2) <= 0);
}
bool intersect(Segment s1, Segment s2)
{
  return intersect(s1.p1, s1.p2, s2.p1, s2.p2);
}
bool intersect(Segment s, Point p)
{
  return (ccw(s.p1, s.p2, p) == ON_SEGMENT);
}
// ?????????????????¢
double getDistance(Point a, Point b)
{
  return abs(a - b);
}
// ??´?????¨?????¨????????¢
double getDistanceLP(Line l, Point p)
{
  return abs(cross(l.p2 - l.p1, p - l.p1) / abs(l.p2 - l.p1));
}
// ????????¨?????¨????????¢
double getDistanceSP(Segment s, Point p)
{
  if(dot(s.p2 - s.p1, p - s.p1) < 0.0) return abs(p - s.p1);
  if(dot(s.p1 - s.p2, p - s.p2) < 0.0) return abs(p - s.p2);
  return getDistanceLP(s, p);
}
// ????????????????????¢
double getDistance(Segment s1, Segment s2)
{
  if(intersect(s1, s2)) return 0.0;
  return min(min(getDistanceSP(s1, s2.p1), getDistanceSP(s1, s2.p2)),
	     min(getDistanceSP(s2, s1.p1), getDistanceSP(s2, s1.p2)));
}
// ???????????????
Point getCrossPoint(Segment s1, Segment s2)
{
  Vector base = s2.p2 - s2.p1;
  double d1 = abs(cross(base, s1.p1 - s2.p1));
  double d2 = abs(cross(base, s1.p2 - s2.p1));
  double t = d1 / (d1 + d2);
  return s1.p1 + (s1.p2 - s1.p1) * t;
}

// ????????????
bool merge_if_able(Segment &s1, Segment s2)
{
  if(abs(cross(s1.p2 - s1.p1, s2.p2 - s2.p1)) > EPS) return false;
  if(ccw(s1.p1, s2.p1, s1.p2) == COUNTER_CLOCKWISE ||
     ccw(s1.p1, s2.p1, s1.p2) == CLOCKWISE) return false;
  if(ccw(s1.p1, s1.p2, s2.p1) == ONLINE_FRONT ||
     ccw(s2.p1, s2.p2, s1.p1) == ONLINE_FRONT) return false;
  s1 = Segment(min(s1.p1, s2.p1), max(s1.p2, s2.p2));
  return true;
}
void merge_segments(vector<Segment>& segs)
{
  for(int i = 0; i < segs.size(); i++) {
    if(segs[i].p2 < segs[i].p1) swap(segs[i].p1, segs[i].p2);
  }
  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();
      }
    }
  }
}
// ????????¢??¬???????????????
typedef vector< vector<int> > Graph;

Graph segment_arrangement(vector<Segment>& segs, vector<Point>& ps)
{
  for(int i = 0; i < segs.size(); i++) {
    ps.push_back(segs[i].p1);
    ps.push_back(segs[i].p2);
    for(int j = i+1; j < segs.size(); j++) {
      if(intersect(segs[i], segs[j])) ps.push_back(getCrossPoint(segs[i], segs[j]));
    }
  }
  sort(ps.begin(), ps.end());
  ps.erase(unique(ps.begin(), ps.end()), ps.end());
  Graph graph(ps.size());
  for(int i = 0; i < segs.size(); i++) {
    vector<int> ls;
    for(int j = 0; j < ps.size(); j++) {
      if(intersect(segs[i], ps[j])) {
	ls.push_back(j);
      }
    }
    sort(ls.begin(), ls.end());
    for(int j = 0; j+1 < ls.size(); j++) {
      int u = ls[j], v = ls[j+1];
      graph[u].push_back(v);
      graph[v].push_back(u);
    }
  }
  return graph;
}

// ???ABC????±???????
double getAngle(Point a, Point b, Point c)
{
  Vector v = b - a, w = c - b;
  double alpha = atan2(v.y, v.x), beta = atan2(w.y, w.x);
  if(alpha > beta) swap(alpha, beta);
  double theta = (beta - alpha) * 180 / M_PI;
  return min(theta, 360 - theta);
}

Graph graph;

double dijkstra(int si, int gi, vector<Point> ps)
{
  vector< vector<double> > mincost(graph.size(), vector<double>(graph.size(),inf));
  // ?????????????????¨??°????????????
  typedef tuple<double, int, int> T;
  priority_queue<T, vector<T>, greater<T> > que;
  for(int to : graph[si]) {
    mincost[to][si] = 0.0;
    que.push(make_tuple(0.0, to, si));
  }  
  while(!que.empty()) {
    double c; int now, prev;
    tie(c, now, prev) = que.top(); que.pop();
    if(now == gi) return c;
    for(int to : graph[now]) {
      double cost = c + getAngle(ps[prev], ps[now], ps[to]);
      if(cost - mincost[to][now] < -EPS) {
	mincost[to][now] = cost;
	que.push(make_tuple(cost, to, now));
      }
    }
  }
  return -1;
}

signed main()
{
  cin.tie(0);
  ios_base::sync_with_stdio(0);
  cout << fixed << setprecision(12);
  int n;
  while(cin >> n, n) {
    vector<Segment> ss(n);
    Point s, g;
    rep(i, n) cin >> ss[i].p1.x >> ss[i].p1.y >> ss[i].p2.x >> ss[i].p2.y;
    cin >> s.x >> s.y >> g.x >> g.y;
    vector<Point> ps;
    merge_segments(ss);
    graph = segment_arrangement(ss, ps);
    int si = -1, gi = -1;
    rep(i, ps.size()) {
      if(ps[i] == s) si = i;
      if(ps[i] == g) gi = i;
    }    
    double ans = dijkstra(si, gi, ps);
    if(ans == -1) cout << -1 << endl;
    else cout << ans << endl;
  }
  return 0;
}