Problem: Brave Ponta has finally arrived at the final dungeon. This is a dark wilderness in front of the fort of the evil emperor Boromos, with fairly strong monsters guarding their territories.

<image>


Figure 1: Wilderness

As shown in Fig. 1, the wilderness is represented by a 4 × 4 square region with the southwest as the origin (0, 0). Inside this area are monsters, as shown by the dots in the figure. Brave Ponta must cross this area from west to east (W to E). That is, you must start from the point where the x coordinate is 0.0 and the y coordinate is 0.0 or more and 4.0 or less, and move to the point where the x coordinate is 4.0 and the y coordinate is 0.0 or more and 4.0 or less.

When an enemy enters the area, the monster attacks the enemy if the distance between him and the enemy is shorter than the distance between any other monster and the enemy.

Now that there are not enough items, it was Ponta who really wanted to avoid fighting as much as possible before fighting Boromos. There, Ponta noticed: If you follow the path where there are always two or more monsters with the shortest distance to you, you won't be attacked by monsters.

Whether the brave Ponta can reach Boromos unscathed depends on your control. Create a program to find the shortest distance through the dark wilderness.

For reference, the shortest path in FIG. 1 is shown in FIG.

<image>


Figure 2: Shortest path



Input

Multiple datasets are given as input. Each dataset is given in the following format:

n (number of monsters: integer)
x1 y1 (Position of the first monster: Real number separated by blanks)
x2 y2 (Position of the second monster: Real number separated by blanks)
..
..
xn yn (position of nth monster: real number separated by blanks)


n is 1 or more and 20 or less. The x and y coordinate values ​​that indicate the position of the monster are 0.0 or more and 4.0 or less.

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

Output

Output the shortest distance on one line for each dataset. If you can't cross the wilderness without being attacked by a monster, print "impossible".

The distance output may have an error of 0.00001 or less.

Example

Input

2
1 1
3 3
4
1.0 0.5
1.0 2.5
3.0 1.5
3.0 3.5
1
2.0 2.0
0


Output

5.656854249492
4.618033988750
impossible

Solution (in CPP):

Solution:
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<map>
#include<set>
#include<iomanip>
#include<ctime>
#include<cassert>
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define F first
#define S second
#define EPS (1e-7)
#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1 
#define ONLINE_BACK 2
#define ONLINE_FRONT -2
#define ON_SEGMENT 0
#define MAX 1000
#define equals(a,b) (fabs((a)-(b)) < EPS)


using namespace std;

class Point
{
  public:
  double x,y;

  Point(double x = -1,double y = -1): 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(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}//※イケメンに限る

  bool operator < (const Point& p) const
  {
    return !equals(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;
  }

//必要に応じて
double norm()
{
return x*x+y*y;
}

};

struct Segment
{
  Point p1,p2;
  Segment(Point p1 = Point(-1,-1),Point p2 = Point(-1,-1)):p1(p1),p2(p2){}
};
typedef Point Vector;
typedef Segment Line;
typedef vector<Point> Polygon;


double dot(Point a,Point b)
{
  return a.x*b.x + a.y*b.y;
}
double cross(Point a,Point b)
{
  return a.x*b.y - a.y*b.x;
}

double norm(Point a)
{
  return a.x*a.x+a.y*a.y;
}



class Voronoi
{
public:
  Polygon poly;
  vector<Point> cutpoints;

  Voronoi(Polygon poly):poly(poly){}

  double norm(Point p){
    return p.x*p.x+p.y*p.y;
  }
 
  double abs(Point p){
    return sqrt(norm(p));
  }
 
  Point polar(double a,double rad){
    return Point(a*cos(rad),a*sin(rad));
  }
 
  double args(Point p){
    return atan2(p.y,p.x);
  }
 
  double dot(Point a,Point b){
    return a.x*b.x+a.y*b.y;
  }
 
  double cross(Point a,Point b){
    return a.x*b.y-b.x*a.y;
  }
 
  Point project(Segment s,Point p){
    Point base = s.p2 - s.p1;
    double t = dot(p-s.p1,base)/base.norm();
    return s.p1+base*t;
  }
 
  Point reflect (Segment s, Point p){
    return p + (project(s,p)-p)*2.0;
  }
 
  int ccw(Point p0,Point p1,Point p2){
    Point a = p1-p0;
    Point 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 isIntersect(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 isIntersect(Segment s1,Segment s2){
    return isIntersect(s1.p1,s1.p2,s2.p1,s2.p2);
  }

  Point getCrossPointSegments(Segment s1,Segment s2){
    //assert(isIntersect(s1,s2));
    Point 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;
  }


  Point getCrossPointLines( Line s1, Line s2){

    Point a = s1.p2 - s1.p1;
    Point base = s2.p2 -s2.p1;
    return s1.p1 + a * (cross(base, s2.p1 - s1.p1)/cross(base, a));
  }

  Polygon cutPolygon( Polygon P, Line l ){
    Polygon u;
    
    for ( int i = 0; i < P.size(); i++ ){
      Point a = P[i], b = P[(i+1)%P.size()];
	
      if ( ccw(l.p1, l.p2, a) != CLOCKWISE ) u.push_back(a);
      if ( ccw(l.p1, l.p2, a) * ccw(l.p1, l.p2, b) == -1 ){
	cutpoints.push_back(getCrossPointLines(Segment(a,b),l));
	u.push_back(getCrossPointLines(Segment(a, b), l));
      }
    }   
    return u;
  } 
 
  Line CreateLine(Point p,Point pp){
    Point mid = (p+pp)/2;
    Point sl = pp-p;//原点に5
    double rad = args(sl);
    Point ap = polar(abs(sl),rad+M_PI/2)+mid;
    //ap.x = abs(sl)*cos(rad+M_PI/2)+mid.x;
    //ap.y = abs(sl)*sin(rad+M_PI/2)+mid.y;
    return Line(mid,ap);
  } 
 
  double AreaCalc(Polygon p){
    double area = 0;
    for(int i=0;i<p.size();i++)
      area+=cross(p[i],p[(i+1)%p.size()]);
    return fabs(area)/2.0;
  } 

  //サイトposに対するボロノイセルV(pos)の面積を返す 
  //pointsは多角形の中に存在するサイトの集合]
  //posはpoints中の自分の位置
  double getAreaOfVoronoi(vector<Point>& points,int pos)
  {
    Polygon polx = poly;
    int N = points.size();
    for(int i=0;i<N;i++)
      if(i != pos)
	polx = cutPolygon(polx,CreateLine(points[pos],points[i]));
    return AreaCalc(polx);
  }  

  /*
   作成中
   points[pos]を基準にcutPolygonした後のpolygonを返す
   */
  vector<Point> getPoints(vector<Point>& points,int pos)
  {
    set<Point> polyS;
    cutpoints.clear();
    for(int i=0;i<poly.size();i++)polyS.insert(poly[i]);
    Polygon polx = poly;
    int N = points.size();
    //  cout << "N = " << N << endl;
    for(int i=0;i<N;i++)
      if(i != pos)
	{
	  polx = cutPolygon(polx,CreateLine(points[pos],points[i]));
	  Line line = CreateLine(points[pos],points[i]);
	  rep(i,4)
	    {
	      if( ccw(line.p1,line.p2,poly[i]) == ON_SEGMENT ||  ccw(line.p1,line.p2,poly[i]) == ONLINE_FRONT ||  ccw(line.p1,line.p2,poly[i]) == ONLINE_BACK)
		{
		  cutpoints.push_back(poly[i]);
		}
	    }
	}

    /*
      cout << "polx ---" << endl;
    rep(i,polx.size())
      {
	cout << polx[i].x << "," << polx[i].y << endl;
      }
    cout << endl;

    cout << "cutpoint ---" <<endl;
    rep(i,cutpoints.size())
      {
	cout << cutpoints[i].x << "," << cutpoints[i].y << endl;
      }
    cout << endl;
    */

    vector<Point> ret;
    for(int i=0;i<polx.size();i++)
      {
	bool ok = false;
	rep(j,cutpoints.size())
	  {
	 
	    if(equals(polx[i].x,cutpoints[j].x) && equals(polx[i].y,cutpoints[j].y))
	      {
		ok = true;
		break;
	      }
	  }
	if(ok)
	  ret.push_back(polx[i]);
      }

    /*
    cout << "ret ---" <<endl;
    rep(i,ret.size())
      {
	cout << ret[i].x << "," << ret[i].y << endl;
      }
    cout << endl;
    */
    return ret;
  }


  vector<Point> getPoints2(vector<Point>& points,int pos)
  {
    set<Point> polyS;
    for(int i=0;i<poly.size();i++)polyS.insert(poly[i]);
    Polygon polx = poly;
    int N = points.size();
    for(int i=0;i<N;i++)
      if(i != pos)
	polx = cutPolygon(polx,CreateLine(points[pos],points[i]));
    /*
    vector<Point> ret;
    const int MOD = 10000000;
    for(int i=0;i<polx.size();i++)
      {
	//if(polyS.find(polx[i]) == polyS.end())
	Point p;

	p.x = floor(polx[i].x*MOD);
	p.x /= MOD;

	p.y = floor(polx[i].y*MOD);
	p.y /= MOD;

	ret.push_back(p);
      }
    */
    return polx;
  }

};

bool check(vector<Point> &vec,Point p)
{
  rep(i,vec.size())
    {
      if(equals(vec[i].x,p.x) && equals(vec[i].y,p.y))return true;
    }
  return false;
}

int getIndex(vector<Point> &prep,Point p)
{
  rep(i,prep.size())
    {
      if(equals(prep[i].x,p.x) && equals(prep[i].y,p.y))
	{
	  return i;
	}
    }

  assert(false);
}

int n;
long double mincost[MAX][MAX];

int main()
{


  /*
  vector<Point> vec(4);
  vec[0] = Point(0,0);
  vec[1] = Point(4,0);
  vec[2] = Point(4,4);
  vec[3] = Point(0,4);

  vector<Point> points;
  points.push_back(Point(1,0.5));
  points.push_back(Point(1,2.5));
  points.push_back(Point(3,1.5));
  points.push_back(Point(3,3.5));
  //points.push_back();
  Voronoi vol(vec);
  vector<Point> that = vol.getPoints(points,1);

  cout << "the area = " << vol.getAreaOfVoronoi(points,1) << endl;

  cout << "that.size() = " << that.size() << endl;
  rep(i,that.size())
    cout << that[i].x << " " << that[i].y << endl; 
  */

  //clock_t start,end;
  //start = clock();
  
  while(cin >> n,n)
    {
      vector<Point> frame(4);
      frame[0] = Point(0,0);
      frame[1] = Point(4,0);
      frame[2] = Point(4,4);
      frame[3] = Point(0,4);
      set<Point> sp;
      rep(i,4)sp.insert(Point(frame[i]));

      Voronoi vol(frame);

      vector<Point> site(n);
      rep(i,n)cin >> site[i].x >> site[i].y;

      vector<Point> prep;
      vector<vector<Point> > material;
     
      rep(i,n)
	{
	  material.push_back(vol.getPoints2(site,i));
	  material[i].push_back(material[i][0]); 
	}



      rep(i,n)
	{
	  vector<Point> crossP = vol.getPoints(site,i);
	  //material.push_back(crossP);
	  rep(j,crossP.size())
	    {
	      bool ok = true;
	      rep(k,prep.size())
		{
		  if(equals(crossP[j].x,prep[k].x) && equals(crossP[j].y,prep[k].y))
		    {
		      ok = false;
		      break;
		    }		  
		}
	      if(ok)
		{
		  prep.push_back(crossP[j]);
		}
	    }
	}

      /*
      cout << "--------" << endl;
      rep(i,prep.size())
	cout << prep[i].x << "," << prep[i].y << endl;
      */
      int N = prep.size();
      vector<vector<double> > G(N,vector<double>(N));
      rep(i,N)rep(j,N)G[i][j] = (i==j?0:1000);
      map<Point,int> index;
      vector<int> ST,ED;


      //cout << "prep === " << endl;
      rep(i,(int)prep.size())
	{
	  //cout << "(" << prep[i].x << "," << prep[i].y << ")" << endl;
	  index[prep[i]] = i;
	  if(equals(prep[i].x,0))ST.push_back(i);
	  if(equals(prep[i].x,4))ED.push_back(i);
	}
      //cout <<"ST = " << ST.size() << ", ED = " << ED.size() << endl;


      
      if(ST.empty() || ED.empty())
	{
	  cout << "impossible" << endl;
	  continue;
	}
      


      rep(i,material.size())
	{
	  int prev = -1;
	  Point pp;
	  //cout << "|||||||||||||||||||||||||||||" << endl;
	  rep(j,material[i].size())
	    {
	      if(!check(prep,material[i][j]))
		{//frame に material[i][j] が含まれるならばアウト
		  prev = -1;
		  continue;	     
		}
	      if(prev == -1)
		{
		  int pes = getIndex(prep,material[i][j]);
		  pp = prep[pes];
		  prev = pes;
		  continue;
		}
	      int next = getIndex(prep,material[i][j]);
	      
	      //cout <<  prev << "(" << pp.x << "," << pp.y << ") is able to go to "<< next << "("<< prep[next].x << "," << prep[next].y << ")" << endl; 
	      if(prev == next)continue;
	      double cost = sqrt(pow(prep[next].x-pp.x,2)+pow(prep[next].y-pp.y,2));
	      G[prev][next] = cost;
	      G[next][prev] = cost;
	      prev = next;
	      pp = prep[next];
	    }
	}
 

      /*
      cout << "N--------------" << endl;
      rep(i,N)cout << "i = " << i << " : (" << prep[i].x << "," << prep[i].y << ")" <<endl;     

      cout << "G--------------" << endl;
      rep(i,N)
	{
	  rep(j,N)
	    {
	      cout.width(10);
	      cout << setiosflags(ios::fixed) << setprecision(10) << G[i][j] << " ";
	      //printf("%.10llf",G[i][j]);
	    }
	  cout << endl;
	}
      */



      for(int k=0;k<N;k++)for(int i=0;i<N;i++)for(int j=0;j<N;j++)G[i][j] = min(G[i][j],G[i][k]+G[k][j]);

      /*
      cout << "------------G-------------" << endl;
      rep(i,N)
	{
	  rep(j,N)
	    {
	      cout.width(10) ;
	      cout << setiosflags(ios::fixed) << setprecision(10) << G[i][j] << " ";
	    }
	  cout << endl;
	}
      cout << endl;
      */

      double ans = 1000;
      rep(i,ST.size())rep(j,ED.size())ans = min(ans,G[ST[i]][ED[j]]);
      cout << setiosflags(ios::fixed) << setprecision(12) << ans << endl;
    }
  //end = clock();
  //cout << setiosflags(ios::fixed) << setprecision(10) << (double)(end-start)/CLOCKS_PER_SEC << endl;

  return 0;
}