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<complex>
#include<vector>
#include<set>
#include<iostream>
#include<stack>
#include<cmath>
#include<queue>

#define FRONT 0x01
#define RIGHT 0x02
#define BACK 0x04
#define LEFT 0x08
#define OVER 0x10

#define CIRCLE_SAME 0x01
#define CIRCLE_CONTAIN 0x02
#define CIRCLE_NO_CROSS 0x04
#define CIRCLE_ONE_CROSS 0x08
#define CIRCLE_ONE_INSIDE_CROSS 0x10
#define CIRCLE_TWO_CROSS 0x20

#define sc second
#define fr first

#define REP(i,n) for(int i = 0; i < (int)(n); ++i)

using namespace std;

typedef double elem;
typedef complex<elem> point, vec;
typedef pair<point, point> line, hline, seg, pp;

const double eps = 1.0e-6;
const double pi = acos(-1.0);
const double infty = 1e40;
point base(0,0);

// oÍ
ostream &operator<<(ostream &os, const pair<point,point> &p){
  os << p.fr << "-" << p.sc;
  return os;
}

// lZ
inline elem sq(elem a){ return a*a; }
inline elem cq(elem a){ return a*a*a; }

// pxÏ·
elem rad(elem deg){ return (deg/180)*pi; }
elem deg(elem rad){ return (rad*180)/pi; }

// ®¬_Ìô¢AÈÇ
bool eq(elem a, elem b){ return abs(a-b) < eps; }
bool lt(elem a, elem b){ return !eq(a,b) && a < b; }
bool leq(elem a, elem b){ return eq(a,b) || a < b; }
bool gt(elem a, elem b){ return !eq(a,b) && a > b; }
bool geq(elem a, elem b){ return eq(a,b) || a > b; }
bool ltz(elem a){ return lt( a, 0 ); }
bool gtz(elem a){ return gt( a, 0 ); }
bool eqv(vec a, vec b){ return eq( abs(b-a),0); }
bool is_zv(vec v){ return eq(abs(v),0); }
elem emax(elem a, elem b){ return gt(a,b)?a:b; }
elem emin(elem a, elem b){ return lt(a,b)?a:b; }

// _Iy[^
bool far(point a, point b){ return gtz( abs(b-a) ); }
bool near(point a, point b){ return leq( abs(b-a), 0 ); }
elem dot(vec a, vec b){ return (a.real() * b.real() + a.imag() * b.imag() ); }
elem cross(vec a, vec b){ return ( a.real() * b.imag() - a.imag() * b.real() ); }

// a©çbÜÅvñèÌpxAàpA]ñ]
elem varg(vec a, vec b){
  elem ret=arg(a)-arg(b);
  if(lt(ret,0))ret+=2*pi;
  if(gt(ret,2*pi))ret-=2*pi;
  if(eq(ret,2*pi))ret=0;
  return ret;
}
elem arg(vec a, vec b){ return acos( dot(a,b) / ( abs(a) * abs(b) ) ); }
point rot(point p, elem theta){ return p * polar((elem)1.0, theta); }
point rotdeg(point p, elem deg){ return p * polar((elem)1.0, rad(deg)); }
point proj(line l, point p){
  double t=dot(p-l.first,l.first-l.second)/abs(l.first-l.second);
  return l.first + t*(l.first-l.second);
}
point reflect(line l, point p){ return p+2.0*(proj(l,p)-p); }

// ñ_Ô£A¼üÆ_ÌÅZ£AüªÆ_ÌÅZ£
elem dist(point a, point b){ return abs(a-b); }
elem dist_l(line l, point x){ return abs(cross(l.sc-l.fr,x-l.fr)) / abs(l.sc-l.fr); }
elem dist_seg(seg s, point x)
{
  if( ltz( dot(s.sc-s.fr,x-s.fr) ) ) return abs(x-s.fr);
  if( ltz( dot(s.fr-s.sc,x-s.sc) ) ) return abs(x-s.sc);
  return dist_l(s,x);
}

// PÊxNgA@üxNgAPÊ@üxNg
vec uvec(vec a){ return a / abs(a); }
vec nmr(vec a){ return a * vec(0,-1); }
vec nml(vec a){ return a * vec(0,1); }
vec unmr(vec a){ return uvec( nmr(a) ); }
vec unml(vec a){ return uvec( nml(a) ); }

// ¼ðA½s»è
bool orth(point a1, point a2, point b1, point b2){ return eq( dot( a2 - a1, b2 - b1 ), 0 ); }
bool orth(vec v1, vec v2){ return eq( dot(v1, v2), 0 ); }
bool prll(point a1, point a2, point b1, point b2){ return eq( cross( a2 - a1, b2 - b1 ), 0 ); }
bool prll(vec v1, vec v2){ return eq( cross(v1, v2), 0 ); }

// CCW oXg¾ªA¸xÉæé
int ccw(point a, point b, point x){
  b -= a;
  x -= a;
  // if( is_zv(b) || is_zv( x ) ) return ERROR;
  if( gtz( cross(b,x) ) ) return LEFT;
  if( ltz( cross(b,x) ) ) return RIGHT;
  if( ltz( dot(b,x) ) ) return BACK;
  if( lt( abs(b), abs(x) ) ) return FRONT;
  return OVER;
}

// üªÌð·»è
bool intersectedSS(seg a, seg b)
{
  if( ccw(a.fr,a.sc,b.fr)&OVER || ccw(a.fr,a.sc,b.sc)&OVER ) return true;
  return
    ( ccw(a.fr,a.sc,b.fr) | ccw(a.fr,a.sc,b.sc) ) == (LEFT|RIGHT) &&
    ( ccw(b.fr,b.sc,a.fr) | ccw(b.fr,b.sc,a.sc) ) == (LEFT|RIGHT) ;
}
// ¼üÌð·»è
bool intersectedLL(line a, line b){ return !eq( cross(a.sc-a.fr,b.sc-b.fr), 0.0 ); }

// ð_vZ
point intersectionSS(seg a, seg b)
{
  elem d1 = dist_l(b,a.fr);
  elem d2 = dist_l(b,a.sc);
  return a.fr + ( d1 / (d1 + d2 ) ) * (a.sc-a.fr);
}
point intersectionLL(line a, line b)
{
  vec va = a.sc - a.fr;
  vec vb = b.sc - b.fr;
  return a.fr + va * ( cross(vb, b.fr - a.fr) / cross(vb,va) );
}

// üªð_êÅ
bool intersectionLL(line a, line b, point &ret){
  return intersectedLL( a, b ) ? ret = intersectionLL( a, b ), true : false;
}
bool intersectionLH(line a, hline b, point &ret){
  point tmp;
  return intersectionLL(a,b,tmp) ? ( ccw(b.fr,b.sc,tmp)&(OVER|FRONT) ? ret=tmp, true : false ) : false;
}
bool intersectionLS(line l, seg s, point &ret){
  point tmp;
  return intersectionLL(l,s,tmp) ? ( ccw(s.fr,s.sc,tmp)&OVER ? ret=tmp, true : false ) : false;
}
bool intersectionHH(hline a, hline b, point &ret){
  point tmp;
  return intersectionLL(a,b,tmp) ? ( ccw(a.fr,a.sc,tmp)&(OVER|FRONT)&&ccw(b.fr,b.sc,tmp)&(OVER|FRONT) ? ret = tmp, true : false ) : false;
}
bool intersectionHS(hline a, seg s, point &ret){
  point tmp;
  return intersectionLS(a,s,tmp) ? ( ccw(a.fr,a.sc,tmp)&(OVER|FRONT) ? ret = tmp, true : false ) : false;
}
bool intersectionSS(seg a, seg b, point &ret){
  return intersectedSS(a,b) ? ret = intersectionSS(a,b), true : false;
}

struct Node{
  point p;
  vector<int> con;
  Node(){}
  Node(point p):p(p){}
};

typedef vector<Node> Graph;

struct State{
  int prev;
  int now;
  double cost;
  State(int prev, int now, double cost):prev(prev),now(now),cost(cost){}
  bool operator>(const State &t)const{
    return cost > t.cost;
  }
};

double weight(int pre, int now, int next, const Graph &G){
  if( now == 0 ) return 0;
  vec a(G[now].p-G[pre].p);
  vec b(G[next].p-G[now].p);
  double ret = varg( a, b );
  // assert(ret>=0);
  return gt(ret,pi)?2*pi-ret:ret;
}

double dijkstra(int st, const Graph &G){
  double ret = infty;
  priority_queue< State, vector<State>, greater<State> > pq;
  bool vis[G.size()+1][G.size()];
  double C[G.size()+1][G.size()];
  for(int i = 0; i < G.size()+1; ++i){
    for(int j = 0; j < G.size(); ++j){
      vis[i][j]=false;
      C[i][j]=infty;
    }
  }
  
  pq.push( State(G.size(),st,0.0) );
  C[G.size()][st]=0;
  while(!pq.empty()){
    State now = pq.top(); pq.pop();
    
    //cout << " PREV : " <<  now.prev << " NOW : " << now.now << " COST : " << now.cost << endl;
    vis[now.prev][now.now] = false;
    
    /*
    if( vis[ now.prev ][ now.now ] ) continue;
    else{
      vis[ now.prev ][ now.now ] =true;
      if( now.now == 1 ){
	//ret = emin( ret, now.cost );
	continue;
      }
    }
    */
    
    const vector<int> &con = G[now.now].con;
    for(int i = 0; i < con.size(); ++i){
      int nextid = con[i];
      double newcost = now.cost + weight(now.prev, now.now, nextid, G);
      if( lt( newcost, C[now.now][nextid] ) ){
	C[now.now][nextid] = newcost;
	if( !vis[now.now][nextid] ){
	  vis[now.now][nextid]=true;
	  State next( now.now, nextid, newcost );
	  pq.push( next );
	}
      }
    }
    
  }

  for(int i = 0; i < G.size()+1; ++i){
    ret = emin( ret, C[i][1] );
  }
  return ret;
}

struct Point{
  point p;
  bool operator<(const Point &t)const{
    return eq(p.real(),t.p.real()) ? lt( p.imag(), t.p.imag() ) : lt(p.real(),t.p.real());
  }
  Point ():p(0,0){}
  Point (point p):p(p){}
};

int main(){
  while(true){
    int n;
    cin >> n;
    if ( n == 0 ) break;
    Graph G;
    set<Point> exist_intersection;
    vector<seg> segs;
    
    for(int i = 0; i < n; ++i){
      elem x1,y1,x2,y2;
      cin >> x1 >> y1 >> x2 >> y2;
      segs.push_back( seg(point(x1,y1),point(x2,y2)) );
    }

    elem sx,sy,gx,gy;cin>>sx>>sy>>gx>>gy;
    G.push_back(point(sx,sy));
    exist_intersection.insert( Point(point(sx,sy)) );
    if(exist_intersection.find(Point(point(gx,gy)))==exist_intersection.end()){
      G.push_back(point(gx,gy));
      exist_intersection.insert(Point(point(gx,gy)));
    }else{
      printf("0.0\n");continue;
    }

    for(int i = 0; i < segs.size(); ++i){
      if( exist_intersection.find(Point(segs[i].fr))==exist_intersection.end()){
	exist_intersection.insert(Point(segs[i].fr));
	G.push_back( segs[i].fr );
      }
      if( exist_intersection.find(Point(segs[i].sc))==exist_intersection.end()){
	exist_intersection.insert(Point(segs[i].sc));
	G.push_back( segs[i].sc );
      }
      for(int j = 0; j < segs.size(); ++j){
	if( i != j ){
	  point tmp;
	  if( intersectionSS( segs[i], segs[j], tmp ) ){
	    if( exist_intersection.find(Point(tmp)) == exist_intersection.end() ){
	      exist_intersection.insert( Point(tmp) );
	      G.push_back( Node(tmp) );
	    }
	  }
	}
      }
    }

    for(int i = 0; i < segs.size(); ++i){
      for(int j = 0; j < G.size(); ++j){
	for(int k = 0; k < G.size(); ++k){
	  if( j != k ){
	    if( ccw( segs[i].fr, segs[i].sc, G[j].p ) == OVER &&
		ccw( segs[i].fr, segs[i].sc, G[k].p ) == OVER ){
	      //cout << G[j].p << ' ' << G[k].p << endl;
	      G[j].con.push_back( k );
	      G[k].con.push_back( j );
	    }
	  }
	}
      }
    }
    
    elem ans = deg( dijkstra( 0, G ) );
    if( geq( ans, infty ) ){
      printf("-1\n");
    }else{
      printf("%.11lf\n",ans);
    }
    
  }
  return 0;
}