#include<iostream>
#include<complex>
#include<queue>
#include<vector>
#include<map>
#include<cmath>
#include<stack>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)

typedef complex<double>P;
const double eps = 1e-10;

class Line{
public:
  P a[2];
  Line(){};
  Line(P &t1,P& t2){
    a[0]=t1;
    a[1]=t2;
  }
};

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

bool operator==(P &a,P &b){
  return a.real()==b.real()&&a.imag()==b.imag();
}

bool is_point_online(P a,P b,P c){
  return (abs(a-c)+abs(b-c)<abs(a-b)+eps);
  return true;
}

double dot(P a,P b){
  return a.real()*b.real()+a.imag()*b.imag();
}
double cross(P a,P b){
  return a.real()*b.imag()-a.imag()*b.real();
} 
P intersection_ls(P a1,P a2,P b1,P b2){
  P b = b2-b1;
  double d1=abs(cross(b,a1-b1));//
  double d2=abs(cross(b,a2-b1));
  double t = d1/(d1+d2);//p[^ t:1-t = d1:d2
  return a1+(a2-a1)*t;
}

void making_group(vector<Line> &in,vector<Line>&edge,vector<Line>&sign,
		  map<P,int> &M,vector<P> &data){
  vector<Line> tmp;
  rep(i,in.size()){
    int cnt0=0,cnt1=0;
    rep(j,in.size()){
      if ( i ==j)continue;
      if ( is_point_online(in[j].a[0],in[j].a[1],in[i].a[0]))cnt0=1;
      if ( is_point_online(in[j].a[0],in[j].a[1],in[i].a[1]))cnt1=1;
    }
    if (cnt0+cnt1==1)sign.push_back(in[i]);//make edge
    else tmp.push_back(in[i]); //make set of node
  }
  rep(i,tmp.size()){
    vector<P> candidate;
    candidate.push_back(tmp[i].a[0]);
    candidate.push_back(tmp[i].a[1]);
    rep(j,tmp.size()){
      if ( is_point_online(tmp[i].a[0],tmp[i].a[1],tmp[j].a[0])){
	
	if ( abs(tmp[i].a[0]-tmp[j].a[0])>eps && abs(tmp[i].a[1]-tmp[j].a[0])>eps)candidate.push_back(tmp[j].a[0]);
      }else if ( is_point_online(tmp[i].a[0],tmp[i].a[1],tmp[j].a[1])){
	if ( abs(tmp[i].a[0]-tmp[j].a[1])>eps && abs(tmp[i].a[1]-tmp[j].a[1])>eps)candidate.push_back(tmp[j].a[1]);
      }
    }
    sort(candidate.begin(),candidate.end());
    rep(j,candidate.size()-1){
      edge.push_back(Line(candidate[j],candidate[j+1]));
    }
    
  }
  

  rep(i,edge.size()){
    rep(j,2){
      if ( M.find(edge[i].a[j])==M.end()){
	int tmp=M.size();M[edge[i].a[j]]=tmp;
	data.push_back(edge[i].a[j]);
      }
    }
  }
}

class Edge{
public:
  int t;
  double c;
  Edge(){};
  Edge(int tt,double tc):t(tt),c(tc){}
};

double dist(P *a){
  return abs(a[0]-a[1]);
}


bool Judge(P &a,P&c,P &d){//c is on a-b
  double val=dot(d-c,a-c);
  if (val >eps)return true;
  else return false;
}
void make_graph(vector<Edge>*edge,vector<Line>&e_set,vector<Line>&sign,
		map<P,int>&M){
  rep(i,e_set.size()){
    bool a0toa1=true,a1toa0=true;
    for(int j=0;j<sign.size()&& (a0toa1||a1toa0);j++){
      if (is_point_online(e_set[i].a[0],e_set[i].a[1],sign[j].a[0])){
	a0toa1=a0toa1&Judge(e_set[i].a[0],sign[j].a[0],sign[j].a[1]);
	a1toa0=a1toa0&Judge(e_set[i].a[1],sign[j].a[0],sign[j].a[1]);
      }else if( is_point_online(e_set[i].a[0],e_set[i].a[1],sign[j].a[1])){
	a0toa1=a0toa1&Judge(e_set[i].a[0],sign[j].a[1],sign[j].a[0]);
	a1toa0=a1toa0&Judge(e_set[i].a[1],sign[j].a[1],sign[j].a[0]);
      }
    }
    if ( a0toa1==true)
      edge[M[e_set[i].a[0]]].push_back(Edge(M[e_set[i].a[1]],dist(e_set[i].a)));
    
    if (a1toa0 ==true)
      edge[M[e_set[i].a[1]]].push_back(Edge(M[e_set[i].a[0]],dist(e_set[i].a)));
  }
  

}

class state{
public:
  int now;
  double c;
  state(){};
  state(int tnow,double tc):now(tnow),c(tc){}
  bool operator<(const state & a)const {
    if (c != a.c)return c > a.c;
    else return now < a.now;
  }
};


const double INF = (1 << 25);
void dijkstra(int s,int t,vector<Edge> *edge,int n,vector<P> &data){
  int path[n];
  double cost[n];
  rep(i,n)path[i]=-1,cost[i]=INF;
  priority_queue<state> Q;
  Q.push(state(s,0));
  cost[s]=0;
  while(!Q.empty()){
    state now = Q.top();
    Q.pop();
    if ( cost[now.now]< now.c)continue;
    if ( now.now == t)break;
    rep(i,edge[now.now].size()){
      if (cost[edge[now.now][i].t] > cost[now.now]+edge[now.now][i].c){
	cost[edge[now.now][i].t]=cost[now.now]+edge[now.now][i].c;
	path[edge[now.now][i].t]=now.now;
	Q.push(state(edge[now.now][i].t,cost[edge[now.now][i].t]));
      }
    }
  }
  if ( path[t] ==-1){puts("-1");return;}

  stack<int> S;
  int now=t;
  while(now != -1){
    S.push(now);
    now=path[now];
  }
  
  while(!S.empty()){
    now=S.top();
    S.pop();
    printf("%.0lf %.0lf\n",data[now].real(),data[now].imag());
  }
  puts("0");
}
	      

main(){
  int n;
  while(cin>>n && n){
    P s,t;
    map<P,int>M;
    cin>>s.real()>>s.imag()>>t.real()>>t.imag();
    M[s]=0;
    M[t]=1;
    vector<Line> in,e_set,sign;
    vector<Edge> edge[500];
    vector<P> data;
    data.push_back(s);data.push_back(t);
    rep(i,n){
      P t1,t2;
      cin>>t1.real()>>t1.imag()>>t2.real()>>t2.imag();
      in.push_back(Line(t1,t2));
    }
    
    making_group(in,e_set,sign,M,data);
    make_graph(edge,e_set,sign,M);
    dijkstra(0,1,edge,M.size(),data);

  }
}

Measured memory_bytes: 1060