#include<iostream>
#include<complex>
#include<vector>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<queue>

using namespace std;

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

#define X real()
#define Y imag()

typedef complex<double> P;
typedef pair<P, P> L;
typedef vector<P> Pol;

const double INF = 1e40;
const double EPS = 1e-8;
const double PI = acos(-1);

int sig(double r) {return (r < -EPS) ? -1 : (r > EPS) ? 1: 0;}
bool eq(double a, double b) {return abs(a - b) < EPS;}
bool near(P a, P b) {return abs(b - a) < EPS;}

// 内積
double dot(P a, P b) {return a.X * b.X + a.Y * b.Y;}
// 外積
double cross(P a, P b) {return a.X * b.Y - a.Y * b.X;}

// 線分のベクトル
P vec(L a) {return a.second - a.first;}

// 線分abに対する点xの位置
enum CCW{FRONT = 1, RIGHT = 2, BACK = 4, LEFT = 8, ON = 16};
int ccw(L s, P p) {
  P a = vec(s);
  p -= s.first;
  double cr = cross(a, p);
  if (eq(cr, 0)) {
    if (sig(dot(a, p)) < 0) return BACK;
    if (sig(norm(a) - norm(p)) < 0) return FRONT;
    return ON;
  }
  return (cr > 0) ? LEFT : RIGHT;
}

// 角度
double ang(P p) {double theta = arg(p); return sig(theta - PI) < 0 ? theta : -PI;}
// 有向角度
double ang(P base, P a, P b) {return ang((b - base) / (a - base));}
P dv(double theta) {return polar(1., theta);}

// 射影
P proj(P a, P b) {return a * dot(a, b) / norm(a);}
P perp(L l, P p) {return l.first + proj(vec(l), p - l.first);}
P refl(L l, P p) {return perp(l, p) * 2. - p;}
 
// 交差判定
bool iLL(L a, L b) {return !eq(cross(vec(a), vec(b)), 0);}
bool eqL(L a, L b) {return !iLL(a, b) && eq(cross(vec(a), b.first - a.first), 0);}
bool iLS(L a, L b) {return sig(cross(vec(a), b.first - a.first)) * sig(cross(vec(a), b.second - a.first)) <= 0;}
bool iLSs(L a, L b) {return sig(cross(vec(a), b.first - a.first)) * sig(cross(vec(a), b.second - a.first)) < 0;}
bool iSS(L a, L b) {
  int cwa = ccw(a, b.first) | ccw(a, b.second);
  int cwb = ccw(b, a.first) | ccw(b, a.second);
  if ((cwa | cwb) & ON) return true;
  return (cwa & cwb) == (LEFT | RIGHT);
}
bool iSSs(L a, L b) {
  return ((ccw(a, b.first) | ccw(a, b.second)) & (ccw(b, a.first) | ccw(b, a.second))) == (LEFT | RIGHT);
}

// 交点
P pLL(L a, L b) {return a.first + vec(a) * (cross(vec(b), b.first - a.first) / cross(vec(b), vec(a)));}

// 距離
double dLP(L l, P x) {return abs(cross(vec(l), x - l.first)) / abs(vec(l));}
double dSP(L s, P x) {
  if (dot(vec(s), x - s.first) <= 0) return abs(x - s.first);
  if (dot(-vec(s), x - s.second) <= 0) return abs(x - s.second);
  return dLP(s, x);
}
double dLL(L a, L b) {return iLL(a, b) ? 0 : dLP(a, b.first);}
double dLS(L a, L b) {return iLS(a, b) ? 0 : min(dLP(a, b.first), dLP(a, b.second));}
double dSS(L a, L b) {return iSS(a, b) ? 0 : min(min(dSP(a, b.first), dSP(a, b.second)), min(dSP(b, a.first), dSP(b, a.second)));}

// 半直線絡みの交差判定
bool iLH(L a, L b) {return iLL(a, b) && ccw(b, pLL(a, b)) & (ON | FRONT);}
bool iHH(L a, L b) {return iLH(a, b) && iLH(b, a);}
bool iHS(L a, L b) {return iLS(a, b) && iLH(b, a);}

// 直行
bool orth(P a, P b) {return eq(dot(a, b), 0);}
// 平行
bool prll(P a, P b) {return eq(cross(a, b), 0);}


// x座標でソート
bool lessX(P a, P b){
  if(!eq(a.X, b.X)) return a.X < b.X;
  if(!eq(a.Y, b.Y)) return a.Y < b.Y;
  return false;
}
// y座標でソート
bool lessY(P a, P b){
  if(!eq(a.Y, b.Y)) return a.Y < b.Y;
  if(!eq(a.X, b.X)) return a.X < b.X;
  return false;
}
// 偏角でソート
L sortBase;
bool lessArg(P a, P b) {
  double ang1 = ang(sortBase.first, sortBase.second, a);
  double ang2 = ang(sortBase.first, sortBase.second, b);
  if (!eq(ang1, ang2)) return ang1 < ang2;
  return norm(a) > norm(b);
}

// 円
struct C{
  P c;
  double r;
  C() {}
  C(P c, double r) : c(c), r(r) {}
};

// 2円の位置関係
enum RELATION{SAME = 1, CONTAIN = 2, OVER = 4, NO_CROSS = 8, ONE_CROSS = 16, ONE_CONTAIN_CROSS = 32, ONE_OVER_CROSS = 64, TWO_CROSS = 128};
int cRel(C c1, C c2) {
  double d = abs(c1.c - c2.c);
  if (near(c1.c, c2.c) && eq(c1.r, c2.r)) return SAME;
  if (sig(d - (c1.r - c2.r)) < 0) return OVER;
  if (sig(d - (c2.r - c1.r)) < 0) return CONTAIN;
  if (eq(d, c1.r - c2.r)) return ONE_OVER_CROSS;
  if (eq(d, c2.r - c1.r)) return ONE_CONTAIN_CROSS;
  if (eq(d, c1.r + c2.r)) return ONE_CROSS;
  if (sig(d - (c1.r + c2.r)) > 0) return NO_CROSS;
  return TWO_CROSS;
}

// 点が円に含まれるか
bool iCP(C c, P p) {return sig(abs(p - c.c) - c.r) <= 0;}
// 交差判定
bool iCL(C c, L l) {return sig(c.r - dLP(l, c.c)) >= 0;}
// 円と交差せず完全に含まれても良い場合は&&以降を削除
bool iCS(C c, L s) {return sig(c.r - dSP(s, c.c)) >= 0 && sig(c.r - max(abs(s.first - c.c), abs(s.second - c.c))) <= 0;}

// 交点
pair<P, P> pCC(C a, C b) {
  double d = abs(b.c - a.c);
  double x = (d * d + a.r * a.r - b.r * b.r) / (2 * d);
  P e = (b.c - a.c) / abs(b.c - a.c), w = e * P(0, 1) * sqrt(max(a.r * a.r - x * x, 0.));
  return make_pair(a.c + e * x - w, a.c + e * x + w);
}
pair<P, P> pCL(C c, L l) {
  P h = perp(l, c.c);
  P e = vec(l) / abs(vec(l)) * sqrt(max(c.r * c.r - norm(h - c.c), 0.0));
  return make_pair(h - e, h + e);
}

// 点から円への接線 firstがp->c.cに対して左側
pair<P, P> tCP(C c, P p) {
  double d2 = norm(p - c.c);
  double x = sqrt(max(d2 - c.r * c.r, 0.));
  P h = c.c + (p - c.c) * (c.r * c.r / d2);
  P w = (p - c.c) * (x * c.r / d2) * P(0, 1);
  return make_pair(h - w, h + w);
}

// 二円の共通接線
// 1個:内側で接する
// 2個:共有点が2個
// 3個:外側で接する
vector<L> tCC(C c1, C c2) {
  vector<L> res;
  pair<P, P> pcross, pcross2;
  double d2 = norm(c2.c - c1.c);

  int rel = cRel(c1, c2);
  if (rel & (SAME | CONTAIN | OVER)) return res;
  
  if (rel & (ONE_CONTAIN_CROSS | ONE_OVER_CROSS | ONE_CROSS)) {
    P p = pCC(c1, c2).first;
    res.push_back(L(p, p + (p - c1.c) * P(0, -1) / abs(p - c1.c)));
    if (rel & (ONE_CONTAIN_CROSS | ONE_OVER_CROSS)) return res;
  }

  //external
  pcross = pCC(C(c1.c, sqrt(d2 - (c2.r - c1.r) * (c2.r - c1.r) + c1.r * c1.r)), c2);
  pcross2 = pCC(C(c2.c, sqrt(d2 - (c2.r - c1.r) * (c2.r - c1.r) + c2.r * c2.r)), c1);
  res.push_back(L(pcross2.second, pcross.first));
  res.push_back(L(pcross2.first, pcross.second));
  if (rel & (TWO_CROSS | ONE_CROSS)) return res;
    
  //internal
  P In((c2.r * c1.c + c1.r * c2.c) / (c1.r + c2.r));
  pcross = pCC(C(In, (abs(c1.c - In)) - (c1.r * c1.r)), c1);
  res.push_back(L(In, pcross.first));
  res.push_back(L(In, pcross.second));
  return res;
}

// 円をn等分する
vector<P> divideCircle(C c, int n, double s) {
  vector<P> v;
  rep (i,n) v.push_back(c.c + c.r * dv(2 * PI / n * i + s));
  return v;
}

// a:bに内分
P iDiv(P p, P q, double a, double b) {return P((q * a + p * b) / (a + b));}
// a:bに外分
P oDiv(P p, P q, double a, double b) {return P((q * a - p * b) / (a - b));}

// 線分を直径とする円
C cDS(L s) {return C((s.first + s.second) / 2., abs(vec(s)) / 2);}
// アポロニウスの円
// s!=tに注意
C apC(P a, P b, double s, double t) {return cDS(L(iDiv(a, b, s, t), oDiv(a, b, s, t)));}

// 角の内外判定 角abの内部にあれば正、辺上は0、外部は負
int sAP(P a, P b, P c) {return sig(cross(a, c)) - sig(cross(b, c)) - sig(cross(a, b));}

// 多角形の面積
double aPol(Pol vp) {
  double ret = 0;
  rep(i, vp.size()){
    ret += cross(vp[i], vp[(i + 1) % vp.size()]);
  }
  return abs(ret / 2);
}
// 正n角形の面積
double aRPol(double r, int n) {return n * r * r * sin(2 * PI / (double)n) / 2.0;}
// 多角形の移動
void movePol(Pol vp, P p) {rep (i, vp.size()) vp[i] += p;}
void rotPol(Pol vp, double theta) {rep (i, vp.size()) vp[i] *= dv(theta);}

// 三角形
struct triangle {
  vector<P> p;
  triangle() : p(3, P(0, 0)) {}
  triangle(P a, P b, P c) {p.push_back(a); p.push_back(b); p.push_back(c);}
  bool contains(P t) {return __builtin_popcount(ccw(L(p[0], p[1]), t) | ccw(L(p[1], p[2]), t) | ccw(L(p[2], p[0]), t)) == 1;}
};

// 長方形
struct rectangle {
  P tl, br;
  rectangle() : tl(0, 0), br(0, 0) {}
  rectangle(P a, P b) : tl(a), br(b) {}
  bool contains(P t) {return tl.X <= t.X && t.X <= br.X && br.Y <= t.Y && t.Y <= tl.Y;}
};

// 点列が反時計回りであるか
// 同一直線上がNGなら(RIGHT | BACK | ON | FRONT)
bool isCounterClockWise(vector<P> vp){
  int n = vp.size();
  rep (i, n) {
    if(ccw(L(vp[i], vp[(i + 1) % n]), vp[(i + 2) % n]) & (RIGHT | BACK | ON))
      return false;
  }
  return true;
}

// 三角形の面積
double aTri(double a, double b, double c){
  double s = (a + b + c) / 2;
  return sqrt(max(s * (s - a) * (s - b) * (s - c), 0.));
}
double aTriSin(double a, double b, double argC){
  return 0.5 * a * b * sin(argC);
}
// 垂線の長さから出す
double aTriH(double Ha, double Hb, double Hc){
  return Hb * Hc / (2 * sin(acos(Hb * Hc * (1. / Hb * Hb + 1. / Hc * Hc - 1. / Ha * Ha) / 2)));
}

// 内接円
P inscribedCircleCenter(P a, P b, P c) {
  double A = abs(c - b), B = abs(c - a), C = abs(b - a);
  double S = A + B + C;
  return (A / S) * a + (B / S) * b + (C / S) * c;
}
// 内接円の半径
double inradiusOfTriangle(double a, double b, double c) {
  return 2 * aTri(a, b, c) / (a + b + c);
}
double inradiusOfTriangle(P a, P b, P c) {
  double A = abs(c - b), B = abs(c - a), C = abs(b - a);
  return 2 * aTri(A, B, C) / (A + B + C);
}

// 球の表面積 xまで部分的に求められる x=rのとき全表面積
double sphereSurface(double r, double x) {return 2 * PI * r * (x + r);}
// 球の体積 xまで部分的に求められる ただしx>=0 x=rのとき全体積
double sphereVolume(double r, double x) {return PI * ((2 / 3.) * r * r * r  + r * r * x - x * x * x / 3.);}

// 三角形の外心を出す
P circumscribedCircleCenter(P a, P b, P c) {
  double ax = a.X, ay = a.Y;
  double bx = b.X, by = b.Y;
  double cx = c.X, cy = c.Y;
  double D = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by));
  return P(((ay * ay + ax * ax) * (by - cy) + by * by + bx * bx * (cy - ay) +
	    (cy * cy + cx * cx) * (ay - by)) / D,
	   ((ay * ay + ax * ax) * (cx - bx) + by * by + bx * bx * (ax - cx) +
	    (cy * cy + cx * cx) * (bx - ax)) / D);
}

// 外接円の半径を出す
double circumscribedCircleRadius(double a, double b, double c) {return a * b * c / (4 * aTri(a, b, c));}

// 多角形の内外判定 内部:1、周上:0、外部:-1
int sGP(Pol pol, P p) {
  int side = -1;
  rep (i, pol.size()) {
    P p0 = pol[i] - p, p1 = pol[(i + 1) % pol.size()] - p;
    if (sig(cross(p0, p1)) == 0 && sig(dot(p0, p1)) <= 0) return 0;
    if (p0.Y > p1.Y) swap(p0, p1);
    if (sig(p0.Y) <= 0 && 0 < sig(p1.Y) && sig(cross(p0, p1)) > 0) side *= -1;
  }
  return side;
}

// 凸包
Pol convexHull(Pol p) {
  int m = 0;
  vector<P> q(p.size() * 2);
  sort(p.begin(), p.end(), lessX);
  for (int i = 0; i < int(p.size()); q[m++] = p[i++]) for (; m > 1 && sig(cross(q[m - 1] - q[m - 2], p[i] - q[m - 2])) <= 0; --m);
  for (int i = p.size() - 2, r = m; i >= 0; q[m++] = p[i--]) for (; m > r && sig(cross(q[m - 1] - q[m - 2], p[i] - q[m - 2])) <= 0; --m);
  q.resize(m - 1);
  return q;
}

// 凸包カット
Pol convexCut(Pol p, L l) {
  vector<P> q;
  rep (i, p.size()) {
    if (ccw(l, p[i]) & (LEFT | BACK | ON | FRONT)) q.push_back(p[i]);
    if (iLSs(l, L(p[i], p[(i + 1) % p.size()]))) q.push_back(pLL(l, L(p[i], p[(i + 1) % p.size()])));
  }
  return q;
}

// 共通コンベックス
vector<P> convexAnd(vector<P> &p1, vector<P> &p2) {
  int n1 = p1.size(), n2 = p2.size();
  vector<P> ret;
  // 凸形同士の交点
  for(int i = 0; i < n1; ++i){
    L li(p1[i], p1[(i + 1) % n1]);
    for(int j = 0; j < n2; ++j){
      L lj(p2[j], p2[(j + 1) % n2]);
      P intersection;
      if(iLL(li, lj)){
	intersection = pLL(li, lj);
	ret.push_back(intersection);
      }
    }
  }
  // それぞれの凸形に含まれる点
  for(int i = 0; i < n1; ++i){
    if(sGP(p2, p1[i]) >= 0){
      ret.push_back(p1[i]);
    }
  }
  for(int i = 0; i < n2; ++i){
    if(sGP(p1, p2[i]) >= 0){
      ret.push_back(p2[i]);
    }
  }
  // 重なり合いを消す
  rep (i, ret.size()){
    rep (j, ret.size()){
      if (near(ret[i], ret[j])){
	ret.erase(ret.begin() + j);
	--i;
	break;
      }
    }
  }
  return convexHull(ret);
}

/*
  　反時計回りの点列で与えられる多角形を三角形で分割する。
  　分割方法は規定しない。
  (LLL,LLR,RLR,RLL)
*/
void triangulate(vector<P> &vp, vector<triangle> &out) {
  vector<P> p = vp;
  string s;
  rep (f, vp.size() * vp.size()) {
    int n = p.size();
    if (n < 3) break;
    int i = (f + 2 * n) % n;
    int vccw = ccw(L(p[i % n], p[(i + 1) % n]), p[(i + 2) % n]);
    switch (vccw) {
    case LEFT: s += 'L'; break;
    case FRONT: p.erase(p.begin()+(i+1)%n);f-=3; continue;
    case RIGHT: s += 'R';
    }
    if(s.length() == 3){
      //cout << s << endl;
      if(s == "LLL" || s == "LLR" || s == "RLR" || s == "RLL"){
	bool doSkip = false;
	triangle t(p[(i - 1 + n) % n], p[i], p[(i + 1) % n]);
	for (int j = 0; j < n; ++j) if (t.contains(p[j])) {doSkip = true; break;}
	if (!doSkip) {out.push_back(t); p.erase(p.begin() + i); f -= 3;}
	else {f -= 2;}
      } else {f -= 2;}
      s = "";
    }
  }
}

// ボロノイ図構築各母点についてのボノロイ頂点が反時計回りに与えられる
vector<Pol> makeVolonoi(vector<P> vp, Pol plane) {
  vector<Pol> res;
  Pol tplane;
  rep (i, vp.size()) {
    tplane = plane;
    rep (j, vp.size()) if (i != j) {
      P p = (vp[i] + vp[j]) / 2.;
      L l = L(p, p + (vp[j] - vp[i]) * P(0, 1));
      tplane = convexCut(tplane, l);
    }
    res.push_back(tplane);
  }
  return res;
}

// 線分をマージする
vector<L> merge(vector<L> s) {
  vector<L> segs;
  bool update = true;
  while (update) {
    update = false;
    rep (i, s.size()) {
      bool ok = true;
      rep (j, segs.size()) {
	if (iSS(s[i], segs[j]) && eq(cross(vec(s[i]), vec(segs[j])), 0)) {
	  vector<P> v;
	  v.push_back(s[i].first);
	  v.push_back(s[i].second);
	  v.push_back(segs[j].first);
	  v.push_back(segs[j].second);
	  sort(v.begin(), v.end(), lessX);
	  segs[j] = L(v[0], v[3]);
	  ok = false;
	  update = true;
	  break;
	}
      }
      if (ok) segs.push_back(s[i]);
    }
    s = segs;
    segs.clear();
  }
  return s;
}

// 線分アレンジメント 隣の点への辺のみを持つ
pair<vector<P>, vector<vector<int> > > sArr(vector<L> s) {
  s = merge(s);
  vector<P> vp;
  rep (i, s.size()) {
    vp.push_back(s[i].first);
    vp.push_back(s[i].second);
  }
  rep (i,s.size()) {
    rep (j, i) if (iSS(s[i], s[j])) {
      vp.push_back(pLL(s[i], s[j]));
    }
  }
  sort(vp.begin(), vp.end(), lessX);
  vp.erase(unique(vp.begin(), vp.end(), near), vp.end());
  vector<vector<int> > g(vp.size());
  rep (i, s.size()) {
    vector<pair<double, int> > v;
    rep (j, vp.size()) if (ccw(s[i], vp[j]) == ON) {
      v.push_back(make_pair(norm(vp[j] - s[i].first), j));
    }
    sort(v.begin(), v.end());
    rep (j, v.size() - 1) {
      g[v[j + 1].second].push_back(v[j].second);
      g[v[j].second].push_back(v[j + 1].second);
    }
  }
  return make_pair(vp, g);
}

// マンハッタン距離
double dmPP(P a, P b) {return abs(a.X - b.X) + abs(a.Y - b.Y);}
double dmSP(L s, P p) {
  double res = min(dmPP(s.first, p), dmPP(s.second, p));
  L l = L(p, p + P(1, 0));
  if (iLS(l, s) && !eq(cross(vec(l), vec(s)), 0)) {
    P pp = pLL(l, s);
    res = min(res, dmPP(p, pp));
  }
  l = L(p, p + P(0, 1));
  if (iLS(l, s) && !eq(cross(vec(l), vec(s)), 0)) {
    P pp = pLL(l, s);
    res = min(res, dmPP(p, pp));
  }
  return res;
}
double dmSS(L a, L b) {return iSS(a, b) ? 0 : min(min(dmSP(a, b.first), dmSP(a, b.second)), min(dmSP(b, a.first), dmSP(b, a.second)));}

int main() {
  int n;
  Pol plane;
  plane.push_back(0);
  plane.push_back(P(4, 0));
  plane.push_back(P(4, 4));
  plane.push_back(P(0, 4));
  for (;;) {
    cin >> n;
    if (n == 0) break;
    vector<P> v;
    rep (i, n) {
      P p;
      cin >> p.X >> p.Y;
      v.push_back(p);
    }
    vector<Pol> vol = makeVolonoi(v, plane);
    vector<L> vs;
    rep (i, n) {
      int m = vol[i].size();
      rep (j, m) {
	if (eq(vol[i][j].X, 0) && eq(vol[i][(j + 1) % m].X, 0)) continue;
	if (eq(vol[i][j].Y, 0) && eq(vol[i][(j + 1) % m].Y, 0)) continue;
	if (eq(vol[i][j].X, 4) && eq(vol[i][(j + 1) % m].X, 4)) continue;
	if (eq(vol[i][j].Y, 4) && eq(vol[i][(j + 1) % m].Y, 4)) continue;
	vs.push_back(L(vol[i][j], vol[i][(j + 1) % m]));
      }
    }
    pair<vector<P>, vector<vector<int> > > arr = sArr(vs);
    vector<P> vp = arr.first;
    vector<vector<int> > vvi = arr.second;
    int m = vp.size();
    vector<double> mem(m);
    rep (i, m) mem[i] = INF;
    priority_queue<pair<double, int>, vector<pair<double, int> >, greater<pair<double, int> > > que;
    rep (i, m) if (eq(vp[i].X, 0)) {
      que.push(make_pair(0, i));
    }
    while (!que.empty()) {
      pair<double, int> now = que.top();
      que.pop();
      if (mem[now.second] <= now.first) continue;
      mem[now.second] = now.first;
      rep (i, vvi[now.second].size()) {
	P next = vp[vvi[now.second][i]];
	que.push(make_pair(now.first + abs(vp[now.second] - next), vvi[now.second][i]));
      }
    }
    double res = INF;
    rep (i, m) if (eq(vp[i].X, 4)) {
      res = min(res, mem[i]);
    }
    if (!eq(res, INF)) printf("%.12lf\n", res);
    else puts("impossible");
  }
  return 0;
}

Measured memory_bytes: 0