Problem:
Complex Paper Folding
Dr. G, an authority in paper folding and one of the directors of
Intercultural Consortium on Paper Crafts,
believes complexity gives figures beauty.
As one of his assistants, your job is to find the way to fold a paper
to obtain the most complex figure.
Dr. G defines the complexity of a figure by the number of vertices.
With the same number of vertices, one with longer perimeter is more
complex.
To simplify the problem, we consider papers with convex polygon in
their shapes and folding them only once.
Each paper should be folded so that one of its vertices exactly lies
on top of another vertex.
Write a program that, for each given convex polygon, outputs the
perimeter of the most complex polygon obtained by folding it once.
Figure 1 (left) illustrates the polygon given in the first dataset of
Sample Input. This happens to be a rectangle.

Folding this rectangle can yield three different polygons illustrated in the Figures 1-a to c by solid
lines.
For this dataset, you should answer the perimeter of the pentagon
shown in Figure 1-a.  Though the rectangle in Figure 1-b has longer
perimeter, the number of vertices takes priority.
(a)
(b)
(c)
Figure 1: The case of the first sample input
Figure 2 (left) illustrates the polygon given in the second
dataset of Sample Input, which is a triangle.  Whichever pair of its vertices are
chosen, quadrangles are obtained as shown in Figures 2-a to c.  Among
these, you should answer the longest perimeter, which is that of the
quadrangle shown in Figure 2-a.
(a)
(b)
(c)
Figure 2: The case of the second sample input
Although we start with a convex polygon, folding it may result a
concave polygon.
Figure 3 (left) illustrates the polygon given in the third dataset in Sample Input.
A concave hexagon shown in Figure 3 (right) can be obtained
by folding it, which has the largest number of vertices.
Figure 3: The case of the third sample input
Figure 4 (left) illustrates the polygon given in the fifth dataset in 
Sample
Input.
Although the perimeter of the polygon in Figure 4-b is longer than that 
of the polygon in Figure 4-a, because the polygon in Figure 4-b is a 
quadrangle, the answer should be the perimeter of the pentagon in Figure
 4-a.
(a)
(b)
Figure 4: The case of the fifth sample input
Input
The input consists of multiple datasets, each in the following format.
n
x
1
y
1
...
x
n
y
n
n
is the number of vertices of the given polygon.
n
is a positive integer satisfying 3 ≤
n
≤ 20.
(
x
i
,
y
i
) gives the coordinates of
the
i
-th vertex.
x
i
and
y
i
are integers
satisfying 0 ≤
x
i
,
y
i
< 1000.
The vertices (
x
1
,
y
1
), ..., (
x
n
,
y
n
)
are given in the counterclockwise order on the
xy
-plane with
y
axis oriented upwards.
You can assume that all the given polygons are convex.
All the possible polygons obtained by folding the given polygon
satisfy the following conditions.
Distance between any two vertices is greater than or equal to 0.00001.
For any three consecutive vertices P, Q, and R, 
...(truncated)

Submitted solutions:

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cassert>
#include <vector>
#include <deque>
typedef long long ll;
typedef long double ld;
//typedef double ld;
const ld INF = 1e17;
const ld TOL = 1e-6;
const ld PI = acos(-1);
const int LEN = 2e3 + 5;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
struct II { int i1, i2; };

int Q, N;
ld ANS[LEN];
int ans = 0;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return { x * p.x + y * p.y }; }
	ld operator / (const Pos& p) const { return { x * p.y - y * p.x }; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos unit() const { return *this / mag(); }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	ld rad() const { return atan2(y, x); }
	int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
	friend bool cmpq(const Pos& a, const Pos& b) { return (a.quad() != b.quad()) ? a.quad() < b.quad() : a / b > 0; }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << p.x << " " << p.y; return os; }
}; const Pos O = { 0, 0 };
typedef std::vector<Pos> Polygon;
struct Linear {//ps[0] -> ps[1] ::
	Pos ps[2];
	Pos dir_;
	const Pos& operator [] (const int& i) const { return ps[i]; }
	const Pos& dir() const { return dir_; }
	Linear(Pos a = Pos(0, 0), Pos b = Pos(0, 0)) {
		ps[0] = a;
		ps[1] = b;
		dir_ = (ps[1] - ps[0]).unit();
	}
	bool include(const Pos& p) const { return sign(dir_ / (p - ps[0])) > 0; }
	friend bool parallel(const Linear& l0, const Linear& l1) { return zero(l0.dir() / l1.dir()); }
	friend bool same_dir(const Linear& l0, const Linear& l1) { return parallel(l0, l1) && l0.dir() * l1.dir() > 0; }
	bool operator < (const Linear& l0) const {
		if (same_dir(*this, l0)) return l0.include(ps[0]);
		else return cmpq(this->dir(), l0.dir());
	}
};
typedef std::vector<Linear> Planes;
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { ld ret = cross(d1, d2, d3); return sign(ret); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
bool on_seg_strong(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) >= 0; }
bool on_seg_weak(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) > 0; }
Pos intersection(const Pos& p1, const Pos& p2, const Pos& q1, const Pos& q2) { ld a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2); return (p1 * a2 + p2 * a1) / (a1 + a2); }
Pos intersection(const Linear& l1, const Linear& l2) { return intersection(l1[0], l1[1], l2[0], l2[1]); }
Polygon half_plane_intersection(std::vector<Linear>& HP) {
	auto check = [&](Linear& u, Linear& v, Linear& w) -> bool {
		return w.include(intersection(u, v));
		};
	std::sort(HP.begin(), HP.end());
	std::deque<Linear> dq;
	int sz = HP.size();
	for (int i = 0; i < sz; ++i) {
		if (i && same_dir(HP[i], HP[(i - 1) % sz])) continue;
		while (dq.size() > 1 && !check(dq[dq.size() - 2], dq[dq.size() - 1], HP[i])) dq.pop_back();
		while (dq.size() > 1 && !check(dq[1], dq[0], HP[i])) dq.pop_front();
		dq.push_back(HP[i]);
	}
	while (dq.size() > 2 && !check(dq[dq.size() - 2], dq[dq.size() - 1], dq[0])) dq.pop_back();
	while (dq.size() > 2 && !check(dq[1], dq[0], dq[dq.size() - 1])) dq.pop_front();
	sz = dq.size();
	if (sz < 3) return {};
	Polygon HPI;
	for (int i = 0; i < sz; ++i) HPI.push_back(intersection(dq[i], dq[(i + 1) % sz]));
	return HPI;
}
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret * .5;
}
ld round(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += (H[i] - H[(i + 1) % sz]).mag();
	return ret;
}
Pos mirror(const Linear& l, const Pos& p) {
	Pos s = l[0], e = l[1];
	if (!ccw(s, e, p)) return p;
	Pos v = ~(e - s);
	Pos m = intersection(s, e, p, p + v);
	v = m - p;
	return p + v + v;
}
int inner_check_bi_search(const std::vector<Pos>& H, const Pos& p) {//convex
	int sz = H.size();
	//if (!sz) return -1;
	//if (sz == 1) return p == H[0] ? 0 : -1;
	//if (sz == 2) return on_seg_strong(H[0], H[1], p) ? 0 : -1;
	assert(sz >= 3);
	if (cross(H[0], H[1], p) < 0 || cross(H[0], H[sz - 1], p) > 0) return -1;
	if (on_seg_strong(H[0], H[1], p) || on_seg_strong(H[0], H[sz - 1], p)) return 0;
	int s = 1, e = sz - 1, m;
	while (s + 1 < e) {
		m = s + e >> 1;
		if (cross(H[0], H[m], p) > 0) s = m;
		else e = m;
	}
	if (cross(H[s], H[e], p) > 0) return 1;
	else if (on_seg_strong(H[s], H[e], p)) return 0;
	else return -1;
}
int inner_check_bi_search_2(const std::vector<Pos>& H, const Pos& p) {//convex
	int sz = H.size();
	//if (!sz) return -1;
	//if (sz == 1) return p == H[0] ? 0 : -1;
	//if (sz == 2) return on_seg_strong(H[0], H[1], p) ? 0 : -1;
	assert(sz >= 3);
	if (cross(H[0], H[1], p) < 0 || cross(H[0], H[sz - 1], p) > 0) return -1;
	if (p == H[0] || p == H[1] || p == H[sz - 1] ) return 1;
	if (on_seg_weak(H[0], H[1], p) || on_seg_weak(H[0], H[sz - 1], p)) return 0;
	//if (on_seg_strong(H[0], H[1], p) || on_seg_strong(H[0], H[sz - 1], p)) return 0;
	int s = 1, e = sz - 1, m;
	while (s + 1 < e) {
		m = s + e >> 1;
		if (cross(H[0], H[m], p) > 0) s = m;
		else e = m;
	}
	if (cross(H[s], H[e], p) > 0) return 2;
	else if (H[s] == p ||  H[e] == p) return 1;
	else if (on_seg_weak(H[s], H[e], p)) return 0;
	//else if (on_seg_strong(H[s], H[e], p)) return 0;
	else return -1;
}
int inner_check(const Polygon& H, const Pos& p) {
	int sz = H.size();
	for (int i = 0; i < sz; i++) {
		int i1 = (i + 1) % sz;
		if (H[i] == p) return 1;
		if (H[i1] == p) return 1;
		if (on_seg_weak(H[i], H[i1], p)) return 0;
		if (ccw(H[i], H[i1], p) < 0) return -1;
	}
	return 2;
}
II find_(const std::vector<Pos>& H, const Pos& p) {//convex
	int sz = H.size();
	//if (!sz) return -1;
	//if (sz == 1) return p == H[0] ? 0 : -1;
	//if (sz == 2) return on_seg_strong(H[0], H[1], p) ? 0 : -1;
	assert(sz >= 3);
	if (cross(H[0], H[1], p) < 0 || cross(H[0], H[sz - 1], p) > 0) return { -1, -1 };
	if (p == H[0]) return { 0, -1 };
	if (p == H[1]) return { 1, -1 };
	if (p == H[sz - 1]) return { sz - 1, -1 };
	if (on_seg_strong(H[0], H[1], p)) return { 0, 1 };
	if (on_seg_strong(H[0], H[sz - 1], p)) return { 0, sz - 1 };
	int s = 1, e = sz - 1, m;
	while (s + 1 < e) {
		m = s + e >> 1;
		if (cross(H[0], H[m], p) > 0) s = m;
		else e = m;
	}
	if (cross(H[s], H[e], p) > 0) return { -1, -1 };
	else if (H[s] == p) return { s, -1 };
	else if (H[e] == p) return { e, -1 };
	else if (on_seg_strong(H[s], H[e], p)) return { s, e };
	else return { -1, -1 };
}
II find(const Polygon& H, const Pos& p) {
	int sz = H.size();
	for (int i = 0; i < sz; i++) {
		int i1 = (i + 1) % sz;
		if (H[i] == p) return { i, -1 };
		if (H[i1] == p) return { i1, -2 };
		if (on_seg_weak(H[i], H[i1], p)) return { i, i1 };
		if (ccw(H[i], H[i1], p) < 0) return { -1, -1 };
	}
	return { -1, -1 };
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	ld ret = 0;
	int V = 0;
	Polygon H(N);
	for (Pos& p : H) std::cin >> p;
	for (int i = 0; i < N; i++) {
		for (int j = i + 1; j < N; j++) {
			Pos m = (H[i] + H[j]) * .5;
			Pos v = ~(H[i] - H[j]);
			Linear I = Linear(m, m + v);
			Linear J = Linear(m, m - v);
			Planes P0, Pi, Pj;
			for (int k = 0; k < N; k++) P0.push_back(Linear(H[k], H[(k + 1) % N]));
			Pi = P0;
			Pi.push_back(I);
			Polygon HI = half_plane_intersection(Pi);
			Pj = P0;
			Pj.push_back(J);
			Polygon HJ = half_plane_intersection(Pj);
			for (Pos& p : HJ) p = mirror(J, p);
			std::reverse(HJ.begin(), HJ.end());
			P0.clear();
			int sz = HI.size();
			for (int k = 0; k < sz; k++) P0.push_back(Linear(HI[k], HI[(k + 1) % sz]));
			sz = HJ.size();
			for (int k = 0; k < sz; k++) P0.push_back(Linear(HJ[k], HJ[(k + 1) % sz]));
			Polygon hpi = half_plane_intersection(P0);
			ld R = round(HI) + round(HJ) - round(hpi);
			int ni = HI.size(), nj = HJ.size();
			int ij = 0;
			for (const Pos& p : HI)
				if (inner_check_bi_search(hpi, p) >= 0 ||
					inner_check_bi_search(HJ, p) >= 0) ni--;
			for (const Pos& p : HJ)
				if (inner_check_bi_search(hpi, p) >= 0 ||
					inner_check_bi_search(HI, p) >= 0) nj--;
			for (const Pos& p : hpi) {
				//int ii = inner_check_bi_search_2(HI, p);
				//int jj = inner_check_bi_search_2(HJ, p);
				int ii = inner_check(HI, p);
				int jj = inner_check(HJ, p);
				//assert(ii != -1 && jj != -1);
				//if (ii == -1 || jj == -1) {
				//	std::cout << "DEBUG:: FUCK::\n";
				//	std::cout << "H = [\n";
				//	for (Pos& p : H) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "hpi = [\n";
				//	for (Pos& p : hpi) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "HI = [\n";
				//	for (Pos& p : HI) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "HJ = [\n";
				//	for (Pos& p : HJ) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "DEBUG:: FUCK::\n";
				//}
				if (ii == 1 && jj == 1) {
					II iii = find(HI, p);
					II jjj = find(HJ, p);
					int i1 = iii.i1, i2 = (i1 + 1) % HI.size(), i0 = (i1 - 1 + HI.size()) % HI.size();
					int j1 = jjj.i1, j2 = (j1 + 1) % HJ.size(), j0 = (j1 - 1 + HJ.size()) % HJ.size();
					//std::cout << i0 << " " << i1 << " " << i2 << "\n";
					//std::cout << j0 << " " << j1 << " " << j2 << "\n";
					if (!ccw(HI[i0], HI[i1], HJ[j2]) || !ccw(HJ[j0], HJ[j1], HI[i2])) ij++;
				}
				else if (ii == 0 && jj == 0) continue;
				else if (ii == 0 && jj == 1) {
					II iii = find(HI, p);
					II jjj = find(HJ, p);
					int i1 = iii.i1, i2 = iii.i2;
					int j1 = jjj.i1, j2 = (j1 + 1) % HJ.size(), j0 = (j1 - 1 + HJ.size()) % HJ.size();
					int c1 = ccw(HI[i1], HI[i2], HJ[j0]);
					int c2 = ccw(HI[i1], HI[i2], HJ[j2]);
					if (!c1 || !c2 || c1 * c2 == 1) ij++;
				}
				else if (ii == 1 && jj == 0) {
					II iii = find(HI, p);
					II jjj = find(HJ, p);
					int j1 = jjj.i1, j2 = jjj.i2;
					int i1 = iii.i1, i2 = (i1 + 1) % HI.size(), i0 = (i1 - 1 + HI.size()) % HI.size();
					int c1 = ccw(HJ[j1], HJ[j2], HI[i0]);
					int c2 = ccw(HJ[j1], HJ[j2], HI[i2]);
					if (!c1 || !c2 || c1 * c2 == 1) ij++;
				}
				else if (ii == 2 || jj == 2) ij++;
			}
			int n = hpi.size() + ni + nj - ij;
			if (V < n) {
				V = n;
				ret = R;
			}
			else if (V == n) {
				V = n;
				ret = std::max(ret, R);
			}//TOTAL O(T * 20 * 20 * 20 * 20) ~= O(T * 16,0000)
		}
	}
	//std::cout << ret << "\n";
	ANS[ans++] = ret;
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (int i = 0; i < ans; i++) std::cout << ANS[i] << "\n";
	return;
}
int main() { solve(); return 0; }//boj11044
accuracy: 1
time_ms: 10
memory_kb: 3488
final_rank: 3

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cassert>
#include <vector>
#include <deque>
typedef long long ll;
typedef long double ld;
//typedef double ld;
const ld INF = 1e17;
const ld TOL = 1e-6;
const ld PI = acos(-1);
const int LEN = 2e3 + 5;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
struct II { int i1, i2; };

int Q, N;
ld ANS[LEN];
int ans = 0;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return { x * p.x + y * p.y }; }
	ld operator / (const Pos& p) const { return { x * p.y - y * p.x }; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos unit() const { return *this / mag(); }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	ld rad() const { return atan2(y, x); }
	int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
	friend bool cmpq(const Pos& a, const Pos& b) { return (a.quad() != b.quad()) ? a.quad() < b.quad() : a / b > 0; }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << p.x << " " << p.y; return os; }
}; const Pos O = { 0, 0 };
typedef std::vector<Pos> Polygon;
struct Linear {//ps[0] -> ps[1] ::
	Pos ps[2];
	Pos dir_;
	const Pos& operator [] (const int& i) const { return ps[i]; }
	const Pos& dir() const { return dir_; }
	Linear(Pos a = Pos(0, 0), Pos b = Pos(0, 0)) {
		ps[0] = a;
		ps[1] = b;
		dir_ = (ps[1] - ps[0]).unit();
	}
	bool include(const Pos& p) const { return sign(dir_ / (p - ps[0])) > 0; }
	friend bool parallel(const Linear& l0, const Linear& l1) { return zero(l0.dir() / l1.dir()); }
	friend bool same_dir(const Linear& l0, const Linear& l1) { return parallel(l0, l1) && l0.dir() * l1.dir() > 0; }
	bool operator < (const Linear& l0) const {
		if (same_dir(*this, l0)) return l0.include(ps[0]);
		else return cmpq(this->dir(), l0.dir());
	}
};
typedef std::vector<Linear> Planes;
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { ld ret = cross(d1, d2, d3); return sign(ret); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
bool on_seg_strong(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) >= 0; }
bool on_seg_weak(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) > 0; }
Pos intersection(const Pos& p1, const Pos& p2, const Pos& q1, const Pos& q2) { ld a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2); return (p1 * a2 + p2 * a1) / (a1 + a2); }
Pos intersection(const Linear& l1, const Linear& l2) { return intersection(l1[0], l1[1], l2[0], l2[1]); }
Polygon half_plane_intersection(std::vector<Linear>& HP) {
	auto check = [&](Linear& u, Linear& v, Linear& w) -> bool {
		return w.include(intersection(u, v));
		};
	std::sort(HP.begin(), HP.end());
	std::deque<Linear> dq;
	int sz = HP.size();
	for (int i = 0; i < sz; ++i) {
		if (i && same_dir(HP[i], HP[(i - 1) % sz])) continue;
		while (dq.size() > 1 && !check(dq[dq.size() - 2], dq[dq.size() - 1], HP[i])) dq.pop_back();
		while (dq.size() > 1 && !check(dq[1], dq[0], HP[i])) dq.pop_front();
		dq.push_back(HP[i]);
	}
	while (dq.size() > 2 && !check(dq[dq.size() - 2], dq[dq.size() - 1], dq[0])) dq.pop_back();
	while (dq.size() > 2 && !check(dq[1], dq[0], dq[dq.size() - 1])) dq.pop_front();
	sz = dq.size();
	if (sz < 3) return {};
	Polygon HPI;
	for (int i = 0; i < sz; ++i) HPI.push_back(intersection(dq[i], dq[(i + 1) % sz]));
	return HPI;
}
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret * .5;
}
ld round(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += (H[i] - H[(i + 1) % sz]).mag();
	return ret;
}
Pos mirror(const Linear& l, const Pos& p) {
	Pos s = l[0], e = l[1];
	if (!ccw(s, e, p)) return p;
	Pos v = ~(e - s);
	Pos m = intersection(s, e, p, p + v);
	v = m - p;
	return p + v + v;
}
int inner_check_bi_search(const std::vector<Pos>& H, const Pos& p) {//convex
	int sz = H.size();
	//if (!sz) return -1;
	//if (sz == 1) return p == H[0] ? 0 : -1;
	//if (sz == 2) return on_seg_strong(H[0], H[1], p) ? 0 : -1;
	assert(sz >= 3);
	if (cross(H[0], H[1], p) < 0 || cross(H[0], H[sz - 1], p) > 0) return -1;
	if (on_seg_strong(H[0], H[1], p) || on_seg_strong(H[0], H[sz - 1], p)) return 0;
	int s = 1, e = sz - 1, m;
	while (s + 1 < e) {
		m = s + e >> 1;
		if (cross(H[0], H[m], p) > 0) s = m;
		else e = m;
	}
	if (cross(H[s], H[e], p) > 0) return 1;
	else if (on_seg_strong(H[s], H[e], p)) return 0;
	else return -1;
}
int inner_check_bi_search_2(const std::vector<Pos>& H, const Pos& p) {//convex
	int sz = H.size();
	//if (!sz) return -1;
	//if (sz == 1) return p == H[0] ? 0 : -1;
	//if (sz == 2) return on_seg_strong(H[0], H[1], p) ? 0 : -1;
	assert(sz >= 3);
	if (cross(H[0], H[1], p) < 0 || cross(H[0], H[sz - 1], p) > 0) return -1;
	if (p == H[0] || p == H[1] || p == H[sz - 1] ) return 1;
	if (on_seg_weak(H[0], H[1], p) || on_seg_weak(H[0], H[sz - 1], p)) return 0;
	//if (on_seg_strong(H[0], H[1], p) || on_seg_strong(H[0], H[sz - 1], p)) return 0;
	int s = 1, e = sz - 1, m;
	while (s + 1 < e) {
		m = s + e >> 1;
		if (cross(H[0], H[m], p) > 0) s = m;
		else e = m;
	}
	if (cross(H[s], H[e], p) > 0) return 2;
	else if (H[s] == p ||  H[e] == p) return 1;
	else if (on_seg_weak(H[s], H[e], p)) return 0;
	//else if (on_seg_strong(H[s], H[e], p)) return 0;
	else return -1;
}
int inner_check(const Polygon& H, const Pos& p) {
	int sz = H.size();
	for (int i = 0; i < sz; i++) {
		int i1 = (i + 1) % sz;
		if (H[i] == p) return 1;
		if (H[i1] == p) return 1;
		if (on_seg_weak(H[i], H[i1], p)) return 0;
		if (ccw(H[i], H[i1], p) < 0) return -1;
	}
	return 2;
}
II find_(const std::vector<Pos>& H, const Pos& p) {//convex
	int sz = H.size();
	//if (!sz) return -1;
	//if (sz == 1) return p == H[0] ? 0 : -1;
	//if (sz == 2) return on_seg_strong(H[0], H[1], p) ? 0 : -1;
	assert(sz >= 3);
	if (cross(H[0], H[1], p) < 0 || cross(H[0], H[sz - 1], p) > 0) return { -1, -1 };
	if (p == H[0]) return { 0, -1 };
	if (p == H[1]) return { 1, -1 };
	if (p == H[sz - 1]) return { sz - 1, -1 };
	if (on_seg_strong(H[0], H[1], p)) return { 0, 1 };
	if (on_seg_strong(H[0], H[sz - 1], p)) return { 0, sz - 1 };
	int s = 1, e = sz - 1, m;
	while (s + 1 < e) {
		m = s + e >> 1;
		if (cross(H[0], H[m], p) > 0) s = m;
		else e = m;
	}
	if (cross(H[s], H[e], p) > 0) return { -1, -1 };
	else if (H[s] == p) return { s, -1 };
	else if (H[e] == p) return { e, -1 };
	else if (on_seg_strong(H[s], H[e], p)) return { s, e };
	else return { -1, -1 };
}
II find(const Polygon& H, const Pos& p) {
	int sz = H.size();
	for (int i = 0; i < sz; i++) {
		int i1 = (i + 1) % sz;
		if (H[i] == p) return { i, -1 };
		if (H[i1] == p) return { i1, -2 };
		if (on_seg_weak(H[i], H[i1], p)) return { i, i1 };
		if (ccw(H[i], H[i1], p) < 0) return { -1, -1 };
	}
	return { -1, -1 };
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	ld ret = 0;
	int V = 0;
	Polygon H(N);
	for (Pos& p : H) std::cin >> p;
	for (int i = 0; i < N; i++) {
		for (int j = i + 1; j < N; j++) {
			Pos m = (H[i] + H[j]) * .5;
			Pos v = ~(H[i] - H[j]);
			Linear I = Linear(m, m + v);
			Linear J = Linear(m, m - v);
			Planes P0, Pi, Pj;
			for (int k = 0; k < N; k++) P0.push_back(Linear(H[k], H[(k + 1) % N]));
			Pi = P0;
			Pi.push_back(I);
			Polygon HI = half_plane_intersection(Pi);
			Pj = P0;
			Pj.push_back(J);
			Polygon HJ = half_plane_intersection(Pj);
			for (Pos& p : HJ) p = mirror(J, p);
			std::reverse(HJ.begin(), HJ.end());
			P0.clear();
			int sz = HI.size();
			for (int k = 0; k < sz; k++) P0.push_back(Linear(HI[k], HI[(k + 1) % sz]));
			sz = HJ.size();
			for (int k = 0; k < sz; k++) P0.push_back(Linear(HJ[k], HJ[(k + 1) % sz]));
			Polygon hpi = half_plane_intersection(P0);
			ld R = round(HI) + round(HJ) - round(hpi);
			int ni = HI.size(), nj = HJ.size();
			int ij = 0;
			for (const Pos& p : HI)
				if (inner_check_bi_search(hpi, p) >= 0 ||
					inner_check_bi_search(HJ, p) >= 0) ni--;
			for (const Pos& p : HJ)
				if (inner_check_bi_search(hpi, p) >= 0 ||
					inner_check_bi_search(HI, p) >= 0) nj--;
			for (const Pos& p : hpi) {
				//int ii = inner_check_bi_search_2(HI, p);
				//int jj = inner_check_bi_search_2(HJ, p);
				int ii = inner_check(HI, p);
				int jj = inner_check(HJ, p);
				//assert(ii != -1 && jj != -1);
				//if (ii == -1 || jj == -1) {
				//	std::cout << "DEBUG:: FUCK::\n";
				//	std::cout << "H = [\n";
				//	for (Pos& p : H) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "hpi = [\n";
				//	for (Pos& p : hpi) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "HI = [\n";
				//	for (Pos& p : HI) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "HJ = [\n";
				//	for (Pos& p : HJ) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "DEBUG:: FUCK::\n";
				//}
				if (ii == 1 && jj == 1) {
					II iii = find(HI, p);
					II jjj = find(HJ, p);
					int i1 = iii.i1, i2 = (i1 + 1) % HI.size(), i0 = (i1 - 1 + HI.size()) % HI.size();
					int j1 = jjj.i1, j2 = (j1 + 1) % HJ.size(), j0 = (j1 - 1 + HJ.size()) % HJ.size();
					//std::cout << i0 << " " << i1 << " " << i2 << "\n";
					//std::cout << j0 << " " << j1 << " " << j2 << "\n";
					if (!ccw(HI[i0], HI[i1], HJ[j2]) || !ccw(HJ[j0], HJ[j1], HI[i2])) ij++;
				}
				else if (ii == 0 && jj == 0) continue;
				else if (ii == 0 && jj == 1) {
					II iii = find(HI, p);
					II jjj = find(HJ, p);
					int i1 = iii.i1, i2 = iii.i2;
					int j1 = jjj.i1, j2 = (j1 + 1) % HJ.size(), j0 = (j1 - 1 + HJ.size()) % HJ.size();
					int c1 = ccw(HI[i1], HI[i2], HJ[j0]);
					int c2 = ccw(HI[i1], HI[i2], HJ[j2]);
					if (!c1 || !c2 || c1 * c2 == 1) ij++;
				}
				else if (ii == 1 && jj == 0) {
					II iii = find(HI, p);
					II jjj = find(HJ, p);
					int j1 = jjj.i1, j2 = jjj.i2;
					int i1 = iii.i1, i2 = (i1 + 1) % HI.size(), i0 = (i1 - 1 + HI.size()) % HI.size();
					int c1 = ccw(HJ[j1], HJ[j2], HI[i0]);
					int c2 = ccw(HJ[j1], HJ[j2], HI[i2]);
					if (!c1 || !c2 || c1 * c2 == 1) ij++;
				}
				else if (ii == 2 || jj == 2) ij++;
			}
			int n = hpi.size() + ni + nj - ij;
			if (V < n) {
				V = n;
				ret = R;
			}
			else if (V == n) {
				V = n;
				ret = std::max(ret, R);
			}//TOTAL O(T * 20 * 20 * 20 * 20) ~= O(T * 16,0000)
		}
	}
	//std::cout << ret << "\n";
	ANS[ans++] = ret;
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (int i = 0; i < ans; i++) std::cout << ANS[i] << "\n";
	return;
}
int main() { solve(); return 0; }//boj11044
accuracy: 1
time_ms: 10
memory_kb: 3652
final_rank: 5

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cassert>
#include <vector>
#include <deque>
typedef long long ll;
typedef long double ld;
//typedef double ld;
const ld INF = 1e17;
const ld TOL = 1e-6;
const ld PI = acos(-1);
const int LEN = 2e3 + 5;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
struct II { int i1, i2; };

int Q, N;
ld ANS[LEN];
int ans = 0;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return { x * p.x + y * p.y }; }
	ld operator / (const Pos& p) const { return { x * p.y - y * p.x }; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos unit() const { return *this / mag(); }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	ld rad() const { return atan2(y, x); }
	int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
	friend bool cmpq(const Pos& a, const Pos& b) { return (a.quad() != b.quad()) ? a.quad() < b.quad() : a / b > 0; }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << p.x << " " << p.y; return os; }
}; const Pos O = { 0, 0 };
typedef std::vector<Pos> Polygon;
struct Linear {//ps[0] -> ps[1] ::
	Pos ps[2];
	Pos dir_;
	const Pos& operator [] (const int& i) const { return ps[i]; }
	const Pos& dir() const { return dir_; }
	Linear(Pos a = Pos(0, 0), Pos b = Pos(0, 0)) {
		ps[0] = a;
		ps[1] = b;
		dir_ = (ps[1] - ps[0]).unit();
	}
	bool include(const Pos& p) const { return sign(dir_ / (p - ps[0])) > 0; }
	friend bool parallel(const Linear& l0, const Linear& l1) { return zero(l0.dir() / l1.dir()); }
	friend bool same_dir(const Linear& l0, const Linear& l1) { return parallel(l0, l1) && l0.dir() * l1.dir() > 0; }
	bool operator < (const Linear& l0) const {
		if (same_dir(*this, l0)) return l0.include(ps[0]);
		else return cmpq(this->dir(), l0.dir());
	}
};
typedef std::vector<Linear> Planes;
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { ld ret = cross(d1, d2, d3); return sign(ret); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
bool on_seg_strong(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) >= 0; }
bool on_seg_weak(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) > 0; }
Pos intersection(const Pos& p1, const Pos& p2, const Pos& q1, const Pos& q2) { ld a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2); return (p1 * a2 + p2 * a1) / (a1 + a2); }
Pos intersection(const Linear& l1, const Linear& l2) { return intersection(l1[0], l1[1], l2[0], l2[1]); }
Polygon half_plane_intersection(std::vector<Linear>& HP) {
	auto check = [&](Linear& u, Linear& v, Linear& w) -> bool {
		return w.include(intersection(u, v));
		};
	std::sort(HP.begin(), HP.end());
	std::deque<Linear> dq;
	int sz = HP.size();
	for (int i = 0; i < sz; ++i) {
		if (i && same_dir(HP[i], HP[(i - 1) % sz])) continue;
		while (dq.size() > 1 && !check(dq[dq.size() - 2], dq[dq.size() - 1], HP[i])) dq.pop_back();
		while (dq.size() > 1 && !check(dq[1], dq[0], HP[i])) dq.pop_front();
		dq.push_back(HP[i]);
	}
	while (dq.size() > 2 && !check(dq[dq.size() - 2], dq[dq.size() - 1], dq[0])) dq.pop_back();
	while (dq.size() > 2 && !check(dq[1], dq[0], dq[dq.size() - 1])) dq.pop_front();
	sz = dq.size();
	if (sz < 3) return {};
	Polygon HPI;
	for (int i = 0; i < sz; ++i) HPI.push_back(intersection(dq[i], dq[(i + 1) % sz]));
	return HPI;
}
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret * .5;
}
ld round(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += (H[i] - H[(i + 1) % sz]).mag();
	return ret;
}
Pos mirror(const Linear& l, const Pos& p) {
	Pos s = l[0], e = l[1];
	if (!ccw(s, e, p)) return p;
	Pos v = ~(e - s);
	Pos m = intersection(s, e, p, p + v);
	v = m - p;
	return p + v + v;
}
int inner_check_bi_search(const std::vector<Pos>& H, const Pos& p) {//convex
	int sz = H.size();
	//if (!sz) return -1;
	//if (sz == 1) return p == H[0] ? 0 : -1;
	//if (sz == 2) return on_seg_strong(H[0], H[1], p) ? 0 : -1;
	assert(sz >= 3);
	if (cross(H[0], H[1], p) < 0 || cross(H[0], H[sz - 1], p) > 0) return -1;
	if (on_seg_strong(H[0], H[1], p) || on_seg_strong(H[0], H[sz - 1], p)) return 0;
	int s = 1, e = sz - 1, m;
	while (s + 1 < e) {
		m = s + e >> 1;
		if (cross(H[0], H[m], p) > 0) s = m;
		else e = m;
	}
	if (cross(H[s], H[e], p) > 0) return 1;
	else if (on_seg_strong(H[s], H[e], p)) return 0;
	else return -1;
}
int inner_check_bi_search_2(const std::vector<Pos>& H, const Pos& p) {//convex
	int sz = H.size();
	//if (!sz) return -1;
	//if (sz == 1) return p == H[0] ? 0 : -1;
	//if (sz == 2) return on_seg_strong(H[0], H[1], p) ? 0 : -1;
	assert(sz >= 3);
	if (cross(H[0], H[1], p) < 0 || cross(H[0], H[sz - 1], p) > 0) return -1;
	if (p == H[0] || p == H[1] || p == H[sz - 1] ) return 1;
	if (on_seg_weak(H[0], H[1], p) || on_seg_weak(H[0], H[sz - 1], p)) return 0;
	//if (on_seg_strong(H[0], H[1], p) || on_seg_strong(H[0], H[sz - 1], p)) return 0;
	int s = 1, e = sz - 1, m;
	while (s + 1 < e) {
		m = s + e >> 1;
		if (cross(H[0], H[m], p) > 0) s = m;
		else e = m;
	}
	if (cross(H[s], H[e], p) > 0) return 2;
	else if (H[s] == p ||  H[e] == p) return 1;
	else if (on_seg_weak(H[s], H[e], p)) return 0;
	//else if (on_seg_strong(H[s], H[e], p)) return 0;
	else return -1;
}
int inner_check(const Polygon& H, const Pos& p) {
	int sz = H.size();
	for (int i = 0; i < sz; i++) {
		int i1 = (i + 1) % sz;
		if (H[i] == p) return 1;
		if (H[i1] == p) return 1;
		if (on_seg_weak(H[i], H[i1], p)) return 0;
		if (ccw(H[i], H[i1], p) < 0) return -1;
	}
	return 2;
}
II find_(const std::vector<Pos>& H, const Pos& p) {//convex
	int sz = H.size();
	//if (!sz) return -1;
	//if (sz == 1) return p == H[0] ? 0 : -1;
	//if (sz == 2) return on_seg_strong(H[0], H[1], p) ? 0 : -1;
	assert(sz >= 3);
	if (cross(H[0], H[1], p) < 0 || cross(H[0], H[sz - 1], p) > 0) return { -1, -1 };
	if (p == H[0]) return { 0, -1 };
	if (p == H[1]) return { 1, -1 };
	if (p == H[sz - 1]) return { sz - 1, -1 };
	if (on_seg_strong(H[0], H[1], p)) return { 0, 1 };
	if (on_seg_strong(H[0], H[sz - 1], p)) return { 0, sz - 1 };
	int s = 1, e = sz - 1, m;
	while (s + 1 < e) {
		m = s + e >> 1;
		if (cross(H[0], H[m], p) > 0) s = m;
		else e = m;
	}
	if (cross(H[s], H[e], p) > 0) return { -1, -1 };
	else if (H[s] == p) return { s, -1 };
	else if (H[e] == p) return { e, -1 };
	else if (on_seg_strong(H[s], H[e], p)) return { s, e };
	else return { -1, -1 };
}
II find(const Polygon& H, const Pos& p) {
	int sz = H.size();
	for (int i = 0; i < sz; i++) {
		int i1 = (i + 1) % sz;
		if (H[i] == p) return { i, -1 };
		if (H[i1] == p) return { i1, -2 };
		if (on_seg_weak(H[i], H[i1], p)) return { i, i1 };
		if (ccw(H[i], H[i1], p) < 0) return { -1, -1 };
	}
	return { -1, -1 };
}
bool query() {//O(2000)
	std::cin >> N;
	if (!N) return 0;
	ld ret = 0;
	int V = 0;
	Polygon H(N);
	for (Pos& p : H) std::cin >> p;
	for (int i = 0; i < N; i++) {
		for (int j = i + 1; j < N; j++) {//(O(2000 * 20 * 20) == O(800000)
			Pos m = (H[i] + H[j]) * .5;
			Pos v = ~(H[i] - H[j]);
			Linear I = Linear(m, m + v);
			Linear J = Linear(m, m - v);
			Planes P0, Pi, Pj;
			for (int k = 0; k < N; k++) P0.push_back(Linear(H[k], H[(k + 1) % N]));
			Pi = P0;
			Pi.push_back(I);
			Polygon HI = half_plane_intersection(Pi);
			Pj = P0;
			Pj.push_back(J);
			Polygon HJ = half_plane_intersection(Pj);
			for (Pos& p : HJ) p = mirror(J, p);
			std::reverse(HJ.begin(), HJ.end());
			P0.clear();
			int sz = HI.size();
			for (int k = 0; k < sz; k++) P0.push_back(Linear(HI[k], HI[(k + 1) % sz]));
			sz = HJ.size();
			for (int k = 0; k < sz; k++) P0.push_back(Linear(HJ[k], HJ[(k + 1) % sz]));
			Polygon hpi = half_plane_intersection(P0);
			ld R = round(HI) + round(HJ) - round(hpi);
			int ni = HI.size(), nj = HJ.size();
			int ij = 0;
			for (const Pos& p : HI)
				if (inner_check_bi_search(hpi, p) >= 0 ||
					inner_check_bi_search(HJ, p) >= 0) ni--;
			for (const Pos& p : HJ)
				if (inner_check_bi_search(hpi, p) >= 0 ||
					inner_check_bi_search(HI, p) >= 0) nj--;
			for (const Pos& p : hpi) {
				//int ii = inner_check_bi_search_2(HI, p);
				//int jj = inner_check_bi_search_2(HJ, p);
				int ii = inner_check(HI, p);
				int jj = inner_check(HJ, p);
				//assert(ii != -1 && jj != -1);
				//if (ii == -1 || jj == -1) {
				//	std::cout << "DEBUG:: FUCK::\n";
				//	std::cout << "H = [\n";
				//	for (Pos& p : H) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "hpi = [\n";
				//	for (Pos& p : hpi) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "HI = [\n";
				//	for (Pos& p : HI) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "HJ = [\n";
				//	for (Pos& p : HJ) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "DEBUG:: FUCK::\n";
				//}
				if (ii == 1 && jj == 1) {
					II iii = find(HI, p);
					II jjj = find(HJ, p);
					int i1 = iii.i1, i2 = (i1 + 1) % HI.size(), i0 = (i1 - 1 + HI.size()) % HI.size();
					int j1 = jjj.i1, j2 = (j1 + 1) % HJ.size(), j0 = (j1 - 1 + HJ.size()) % HJ.size();
					//std::cout << i0 << " " << i1 << " " << i2 << "\n";
					//std::cout << j0 << " " << j1 << " " << j2 << "\n";
					if (!ccw(HI[i0], HI[i1], HJ[j2]) || !ccw(HJ[j0], HJ[j1], HI[i2])) ij++;
				}
				else if (ii == 0 && jj == 0) continue;
				else if (ii == 0 && jj == 1) {
					II iii = find(HI, p);
					II jjj = find(HJ, p);
					int i1 = iii.i1, i2 = iii.i2;
					int j1 = jjj.i1, j2 = (j1 + 1) % HJ.size(), j0 = (j1 - 1 + HJ.size()) % HJ.size();
					int c1 = ccw(HI[i1], HI[i2], HJ[j0]);
					int c2 = ccw(HI[i1], HI[i2], HJ[j2]);
					if (!c1 || !c2 || c1 * c2 == 1) ij++;
				}
				else if (ii == 1 && jj == 0) {
					II iii = find(HI, p);
					II jjj = find(HJ, p);
					int j1 = jjj.i1, j2 = jjj.i2;
					int i1 = iii.i1, i2 = (i1 + 1) % HI.size(), i0 = (i1 - 1 + HI.size()) % HI.size();
					int c1 = ccw(HJ[j1], HJ[j2], HI[i0]);
					int c2 = ccw(HJ[j1], HJ[j2], HI[i2]);
					if (!c1 || !c2 || c1 * c2 == 1) ij++;
				}
				else if (ii == 2 || jj == 2) ij++;
			}
			int n = hpi.size() + ni + nj - ij;
			if (V < n) {
				V = n;
				ret = R;
			}
			else if (V == n) {
				V = n;
				ret = std::max(ret, R);
			}//TOTAL O(2000 * 20 * 20 * 20 * 20) ~= O(3,2000,0000)
		}
	}
	//std::cout << ret << "\n";
	ANS[ans++] = ret;
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (int i = 0; i < ans; i++) std::cout << ANS[i] << "\n";
	return;
}
int main() { solve(); return 0; }//boj11044
accuracy: 1
time_ms: 10
memory_kb: 3580
final_rank: 4

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cassert>
#include <vector>
#include <deque>
typedef long long ll;
typedef long double ld;
//typedef double ld;
const ld INF = 1e17;
const ld TOL = 1e-6;
const ld PI = acos(-1);
const int LEN = 2e3 + 5;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
struct II { int i1, i2; };

int Q, N;
ld ANS[LEN];
int ans = 0;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return { x * p.x + y * p.y }; }
	ld operator / (const Pos& p) const { return { x * p.y - y * p.x }; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos unit() const { return *this / mag(); }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	ld rad() const { return atan2(y, x); }
	int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
	friend bool cmpq(const Pos& a, const Pos& b) { return (a.quad() != b.quad()) ? a.quad() < b.quad() : a / b > 0; }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << p.x << " " << p.y; return os; }
}; const Pos O = { 0, 0 };
typedef std::vector<Pos> Polygon;
struct Linear {//ps[0] -> ps[1] ::
	Pos ps[2];
	Pos dir_;
	const Pos& operator [] (const int& i) const { return ps[i]; }
	const Pos& dir() const { return dir_; }
	Linear(Pos a = Pos(0, 0), Pos b = Pos(0, 0)) {
		ps[0] = a;
		ps[1] = b;
		dir_ = (ps[1] - ps[0]).unit();
	}
	bool include(const Pos& p) const { return sign(dir_ / (p - ps[0])) > 0; }
	friend bool parallel(const Linear& l0, const Linear& l1) { return zero(l0.dir() / l1.dir()); }
	friend bool same_dir(const Linear& l0, const Linear& l1) { return parallel(l0, l1) && l0.dir() * l1.dir() > 0; }
	bool operator < (const Linear& l0) const {
		if (same_dir(*this, l0)) return l0.include(ps[0]);
		else return cmpq(this->dir(), l0.dir());
	}
};
typedef std::vector<Linear> Planes;
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { ld ret = cross(d1, d2, d3); return sign(ret); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
bool on_seg_strong(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) >= 0; }
bool on_seg_weak(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) > 0; }
Pos intersection(const Pos& p1, const Pos& p2, const Pos& q1, const Pos& q2) { ld a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2); return (p1 * a2 + p2 * a1) / (a1 + a2); }
Pos intersection(const Linear& l1, const Linear& l2) { return intersection(l1[0], l1[1], l2[0], l2[1]); }
Polygon half_plane_intersection(std::vector<Linear>& HP) {
	auto check = [&](Linear& u, Linear& v, Linear& w) -> bool {
		return w.include(intersection(u, v));
		};
	std::sort(HP.begin(), HP.end());
	std::deque<Linear> dq;
	int sz = HP.size();
	for (int i = 0; i < sz; ++i) {
		if (i && same_dir(HP[i], HP[(i - 1) % sz])) continue;
		while (dq.size() > 1 && !check(dq[dq.size() - 2], dq[dq.size() - 1], HP[i])) dq.pop_back();
		while (dq.size() > 1 && !check(dq[1], dq[0], HP[i])) dq.pop_front();
		dq.push_back(HP[i]);
	}
	while (dq.size() > 2 && !check(dq[dq.size() - 2], dq[dq.size() - 1], dq[0])) dq.pop_back();
	while (dq.size() > 2 && !check(dq[1], dq[0], dq[dq.size() - 1])) dq.pop_front();
	sz = dq.size();
	if (sz < 3) return {};
	Polygon HPI;
	for (int i = 0; i < sz; ++i) HPI.push_back(intersection(dq[i], dq[(i + 1) % sz]));
	return HPI;
}
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret * .5;
}
ld round(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += (H[i] - H[(i + 1) % sz]).mag();
	return ret;
}
Pos mirror(const Linear& l, const Pos& p) {
	Pos s = l[0], e = l[1];
	if (!ccw(s, e, p)) return p;
	Pos v = ~(e - s);
	Pos m = intersection(s, e, p, p + v);
	v = m - p;
	return p + v + v;
}
int inner_check_bi_search(const std::vector<Pos>& H, const Pos& p) {//convex
	int sz = H.size();
	//if (!sz) return -1;
	//if (sz == 1) return p == H[0] ? 0 : -1;
	//if (sz == 2) return on_seg_strong(H[0], H[1], p) ? 0 : -1;
	assert(sz >= 3);
	if (cross(H[0], H[1], p) < 0 || cross(H[0], H[sz - 1], p) > 0) return -1;
	if (on_seg_strong(H[0], H[1], p) || on_seg_strong(H[0], H[sz - 1], p)) return 0;
	int s = 0, e = sz - 1, m;
	while (s + 1 < e) {
		m = s + e >> 1;
		if (cross(H[0], H[m], p) > 0) s = m;
		else e = m;
	}
	if (cross(H[s], H[e], p) > 0) return 1;
	else if (on_seg_strong(H[s], H[e], p)) return 0;
	else return -1;
}
int inner_check_bi_search_2(const std::vector<Pos>& H, const Pos& p) {//convex
	int sz = H.size();
	//if (!sz) return -1;
	//if (sz == 1) return p == H[0] ? 0 : -1;
	//if (sz == 2) return on_seg_strong(H[0], H[1], p) ? 0 : -1;
	assert(sz >= 3);
	if (cross(H[0], H[1], p) < 0 || cross(H[0], H[sz - 1], p) > 0) return -1;
	if (p == H[0] || p == H[1] || p == H[sz - 1] ) return 1;
	if (on_seg_weak(H[0], H[1], p) || on_seg_weak(H[0], H[sz - 1], p)) return 0;
	//if (on_seg_strong(H[0], H[1], p) || on_seg_strong(H[0], H[sz - 1], p)) return 0;
	int s = 0, e = sz - 1, m;
	while (s + 1 < e) {
		m = s + e >> 1;
		if (cross(H[0], H[m], p) > 0) s = m;
		else e = m;
	}
	if (cross(H[s], H[e], p) > 0) return 2;
	else if (H[s] == p ||  H[e] == p) return 1;
	else if (on_seg_weak(H[s], H[e], p)) return 0;
	//else if (on_seg_strong(H[s], H[e], p)) return 0;
	else return -1;
}
int inner_check(const Polygon& H, const Pos& p) {
	int sz = H.size();
	for (int i = 0; i < sz; i++) {
		int i1 = (i + 1) % sz;
		if (H[i] == p) return 1;
		if (H[i1] == p) return 1;
		if (on_seg_weak(H[i], H[i1], p)) return 0;
		if (ccw(H[i], H[i1], p) < 0) return -1;
	}
	return 2;
}
II find_(const std::vector<Pos>& H, const Pos& p) {//convex
	int sz = H.size();
	//if (!sz) return -1;
	//if (sz == 1) return p == H[0] ? 0 : -1;
	//if (sz == 2) return on_seg_strong(H[0], H[1], p) ? 0 : -1;
	assert(sz >= 3);
	if (cross(H[0], H[1], p) < 0 || cross(H[0], H[sz - 1], p) > 0) return { -1, -1 };
	if (p == H[0]) return { 0, -1 };
	if (p == H[1]) return { 1, -1 };
	if (p == H[sz - 1]) return { sz - 1, -1 };
	if (on_seg_strong(H[0], H[1], p)) return { 0, 1 };
	if (on_seg_strong(H[0], H[sz - 1], p)) return { 0, sz - 1 };
	int s = 0, e = sz - 1, m;
	while (s + 1 < e) {
		m = s + e >> 1;
		if (cross(H[0], H[m], p) > 0) s = m;
		else e = m;
	}
	if (cross(H[s], H[e], p) > 0) return { -1, -1 };
	else if (H[s] == p) return { s, -1 };
	else if (H[e] == p) return { e, -1 };
	else if (on_seg_strong(H[s], H[e], p)) return { s, e };
	else return { -1, -1 };
}
II find(const Polygon& H, const Pos& p) {
	int sz = H.size();
	for (int i = 0; i < sz; i++) {
		int i1 = (i + 1) % sz;
		if (H[i] == p) return { i, -1 };
		if (H[i1] == p) return { i1, -2 };
		if (on_seg_weak(H[i], H[i1], p)) return { i, i1 };
		if (ccw(H[i], H[i1], p) < 0) return { -1, -1 };
	}
	return { -1, -1 };
}
bool query() {//O(2000)
	std::cin >> N;
	if (!N) return 0;
	ld ret = 0;
	int V = 0;
	Polygon H(N);
	for (Pos& p : H) std::cin >> p;
	for (int i = 0; i < N; i++) {
		for (int j = i + 1; j < N; j++) {//(O(2000 * 20 * 20) == O(800000)
			Pos m = (H[i] + H[j]) * .5;
			Pos v = ~(H[i] - H[j]);
			Linear I = Linear(m, m + v);
			Linear J = Linear(m, m - v);
			Planes P0, Pi, Pj;
			for (int k = 0; k < N; k++) P0.push_back(Linear(H[k], H[(k + 1) % N]));
			Pi = P0;
			Pi.push_back(I);
			Polygon HI = half_plane_intersection(Pi);
			Pj = P0;
			Pj.push_back(J);
			Polygon HJ = half_plane_intersection(Pj);
			for (Pos& p : HJ) p = mirror(J, p);
			std::reverse(HJ.begin(), HJ.end());
			P0.clear();
			int sz = HI.size();
			for (int k = 0; k < sz; k++) P0.push_back(Linear(HI[k], HI[(k + 1) % sz]));
			sz = HJ.size();
			for (int k = 0; k < sz; k++) P0.push_back(Linear(HJ[k], HJ[(k + 1) % sz]));
			Polygon hpi = half_plane_intersection(P0);
			ld R = round(HI) + round(HJ) - round(hpi);
			int ni = HI.size(), nj = HJ.size();
			int ij = 0;
			for (const Pos& p : HI)
				if (inner_check_bi_search(hpi, p) >= 0 ||
					inner_check_bi_search(HJ, p) >= 0) ni--;
			for (const Pos& p : HJ)
				if (inner_check_bi_search(hpi, p) >= 0 ||
					inner_check_bi_search(HI, p) >= 0) nj--;
			for (const Pos& p : hpi) {
				//int ii = inner_check_bi_search_2(HI, p);
				//int jj = inner_check_bi_search_2(HJ, p);
				int ii = inner_check(HI, p);
				int jj = inner_check(HJ, p);
				//assert(ii != -1 && jj != -1);
				//if (ii == -1 || jj == -1) {
				//	std::cout << "DEBUG:: FUCK::\n";
				//	std::cout << "H = [\n";
				//	for (Pos& p : H) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "hpi = [\n";
				//	for (Pos& p : hpi) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "HI = [\n";
				//	for (Pos& p : HI) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "HJ = [\n";
				//	for (Pos& p : HJ) std::cout << "(" << p.x << ", " << p.y << "),\n";
				//	std::cout << "]\n";
				//	std::cout << "DEBUG:: FUCK::\n";
				//}
				if (ii == 1 && jj == 1) {
					II iii = find(HI, p);
					II jjj = find(HJ, p);
					int i1 = iii.i1, i2 = (i1 + 1) % HI.size(), i0 = (i1 - 1 + HI.size()) % HI.size();
					int j1 = jjj.i1, j2 = (j1 + 1) % HJ.size(), j0 = (j1 - 1 + HJ.size()) % HJ.size();
					//std::cout << i0 << " " << i1 << " " << i2 << "\n";
					//std::cout << j0 << " " << j1 << " " << j2 << "\n";
					if (!ccw(HI[i0], HI[i1], HJ[j2]) || !ccw(HJ[j0], HJ[j1], HI[i2])) ij++;
				}
				else if (ii == 0 && jj == 0) continue;
				else if (ii == 0 && jj == 1) {
					II iii = find(HI, p);
					II jjj = find(HJ, p);
					int i1 = iii.i1, i2 = iii.i2;
					int j1 = jjj.i1, j2 = (j1 + 1) % HJ.size(), j0 = (j1 - 1 + HJ.size()) % HJ.size();
					int c1 = ccw(HI[i1], HI[i2], HJ[j0]);
					int c2 = ccw(HI[i1], HI[i2], HJ[j2]);
					if (!c1 || !c2 || c1 * c2 == 1) ij++;
				}
				else if (ii == 1 && jj == 0) {
					II iii = find(HI, p);
					II jjj = find(HJ, p);
					int j1 = jjj.i1, j2 = jjj.i2;
					int i1 = iii.i1, i2 = (i1 + 1) % HI.size(), i0 = (i1 - 1 + HI.size()) % HI.size();
					int c1 = ccw(HJ[j1], HJ[j2], HI[i0]);
					int c2 = ccw(HJ[j1], HJ[j2], HI[i2]);
					if (!c1 || !c2 || c1 * c2 == 1) ij++;
				}
				else if (ii == 2 || jj == 2) ij++;
			}
			int n = hpi.size() + ni + nj - ij;
			if (V < n) {
				V = n;
				ret = R;
			}
			else if (V == n) {
				V = n;
				ret = std::max(ret, R);
			}//TOTAL O(2000 * 20 * 20 * 20 * log(20)) ~= O(80000000)
		}
	}
	//std::cout << ret << "\n";
	ANS[ans++] = ret;
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (int i = 0; i < ans; i++) std::cout << ANS[i] << "\n";
	return;
}
int main() { solve(); return 0; }//boj11044
accuracy: 1
time_ms: 10
memory_kb: 3652
final_rank: 5

code_snippet: //#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
const ll mod = 998244353;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 2;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}



typedef complex<ld> Point;
ld dot(Point a, Point b) { return real(conj(a) * b); }
ld cross(Point a, Point b) { return imag(conj(a) * b); }
namespace std {
	bool operator<(const Point& lhs, const Point& rhs) {
		return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
	}
}
struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
int ccw(Point a, Point b, Point c) {
	b -= a; c -= a;
	if (cross(b, c) > eps)return 1;//counter clockwise
	if (cross(b, c) < -eps)return -1;//clock wise
	if (dot(b, c) < 0)return 2;//c--a--b on line
	if (norm(b) < norm(c))return -2;//a--b--c on line
	return 0; //a--c--b on line
}
bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
//2直線の交差判定
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
//直線と線分の交差判定
bool isis_ls(Line l, Line s) {
	return (cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}
//点が直線上に存在するか
bool isis_lp(Line l, Point p) {
	return (abs(cross(l.b - p, l.a - p)) < eps);
}
//点が線分上に存在するか
bool isis_sp(Line s, Point p) {
	//誤差がisis_lpに比べて大きいので、できるだけisis_lpを使う
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
//線分と線分の交差判定
//bool isis_ss(Line s, Line t) {
//	return(cross(s.b - s.a, t.a - s.a)*cross(s.b - s.a, t.b - s.a) < -eps && cross(t.b - t.a, s.a - t.a)*cross(t.b - t.a, s.b - t.a) < -eps);
//}
//線分と線分の交差判定2
bool isis_ss(Line s, Line t) {
	return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}
//点から直線への垂線の足
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
//直線と直線の交点
//平行な２直線に対しては使うな！！！！
Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a; Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}
typedef vector<Point> polygon;
polygon ConvexHull(polygon p) {
	int n = p.size();
	int k = 0;
	sort(p.begin(), p.end());
	polygon ch(2 * n);
	for (int i = 0; i < n; ch[k++] = p[i++]) {
		while (k >= 2 && ccw(ch[k - 2], ch[k - 1], p[i]) <= 0)--k;
	}
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) {
		while (k >= t && ccw(ch[k - 2], ch[k - 1], p[i]) <= 0)--k;
	}
	ch.resize(k - 1);
	return ch;
}
ld area(const polygon& p) {
	ld ret = 0;
	int n = p.size();
	rep(j, n)ret += cross(p[j], p[(j + 1) % n]);
	return ret / 2.0;
}
polygon convex_cut(const polygon& p, Line l) {
	vector<Point> ret;
	rep(i, p.size()) {
		Point a = p[i], b = p[(i + 1) % p.size()];
		if (ccw(l.a, l.b, a) == 1)ret.push_back(a);
		if (ccw(l.a, l.b, a) * ccw(l.a, l.b, b) < 0) {
			ret.push_back(is_ll({ a,b }, l));
		}
	}
	return ret;
}
//2点の垂直二等分線
Line mid_line(Point a, Point b) {
	ld mx = (real(a) + real(b)) / 2.0, my = (imag(a) + imag(b)) / 2.0;
	ld dx = real(b) - real(a), dy = imag(b) - imag(a);
	swap(dx, dy); dx = -dx;
	Point le = { mx - dx,my - dy }, ri = { mx + dx,my + dy };
	//a,le,ri is counter clockwise
	return { le,ri };
}
vector<Point> is_ss(Line s1, Line s2) {
	if (!isis_ss(s1, s2))return {};
	vector<Point> res;
	if (abs(cross(s1.b - s1.a, s2.b - s2.a)) < eps) {
		if (isis_sp(s1, s2.a)) res.push_back(s2.a);
		if (isis_sp(s1, s2.b)) res.push_back(s2.b);
		if (isis_sp(s2, s1.a)) res.push_back(s1.a);
		if (isis_sp(s2, s1.b)) res.push_back(s1.b);
	}
	else {
		res.push_back(is_ll(s1, s2));
	}
	return res;
}
int is_in_polygon(polygon& poly, Point p) {
	ld sum = 0;
	int n = poly.size();
	rep(i, n) {
		int ni = i + 1 == n ? 0 : i + 1;
		Point pl = poly[i];
		Point pr = poly[ni];
		Line e = { pl,pr };
		if (isis_sp(e, p))return 0;
		sum += arg((pr - p) / (pl - p));
	}
	if (abs(sum) < pi / 2)return 2;
	return 1;
}
Point rev(Line l, Point p) {
	Point h = proj(l, p);
	return h + (h - p);
}

int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

vector<Line> outside(polygon& pl, polygon& pr) {
	vector<Line> res;
	rep(x, pl.size()) {
		vector<ld> ts;
		ts.push_back(0);
		ts.push_back(1);
		int nx = x + 1 == pl.size() ? 0 : x + 1;
		Line l1 = { pl[x],pl[nx] };
		rep(y, pr.size()) {
			int ny = y + 1 == pr.size() ? 0 : y + 1;
			Line l2 = { pr[y],pr[ny] };
			if (isis_ss(l1, l2)) {
				auto vp = is_ss(l1, l2);
				for (Point p : vp) {
					ld t = abs(p - l1.a) / (abs(l1.b - l1.a));
					ts.push_back(t);
				}
			}
		}
		sort(all(ts));
		rep(k, ts.size() - 1) {
			if (abs(ts[k] - ts[k + 1]) < eps)continue;
			Point lp = l1.a + (l1.b - l1.a) * ts[k];
			Point rp = l1.a + (l1.b - l1.a) * ts[k + 1];
			Point mp = (lp + rp) / (ld)2.0;
			if (is_in_polygon(pr, mp) != 1) {
				res.push_back({ lp,rp });
			}
		}
	}
	//cout << res.size() << "\n";
	return res;
}
int n;
void solve() {
	vector<Point> p(n);
	rep(i, n) {
		int x, y; cin >> x >> y;
		p[i] = { (ld)x,(ld)y };
	}
	int macnt = -1;
	ld malen = -1;
	rep(i, n)Rep(j, i + 1, n) {
		//p[i] and p[j]
		Line l = mid_line(p[i], p[j]);
		polygon pl = p, pr = p;
		pl = convex_cut(pl, l);
		swap(l.a, l.b);
		pr = convex_cut(pr, l);
		rep(i, pr.size()) {
			pr[i] = rev(l, pr[i]);
		}
		reverse(all(pr));
		//cout << i << " " << j << "\n";
		vector<Line> lv;
		auto x = outside(pl, pr);
		for (Line l : x)lv.push_back(l);
		x = outside(pr, pl);
		for (Line l : x)lv.push_back(l);
		vector<Point> nw;
		auto trans = [&](Point& p) {
			rep(i, nw.size()) {
				if (abs(nw[i] - p) < eps) {
					p = nw[i];
					return true;
				}
			}
			return false;
		};
		ld anslen = 0;
		vector<bool> e(lv.size());
		rep(i, lv.size()) {
			Line& z = lv[i];
			if (!trans(z.a))nw.push_back(z.a);
			if (!trans(z.b))nw.push_back(z.b);
			if (z.b < z.a)swap(z.a, z.b);
			bool exi = false;
			rep(j, i)if (abs(lv[i].a - lv[j].a) < eps && abs(lv[i].b - lv[j].b) < eps)exi = true;
			if (!exi) {
				anslen += abs(lv[i].b - lv[i].a);
			}
			e[i] = exi;
		}
		int anscnt = 0;
		rep(i, nw.size()) {
			vector<Point> vp;
			rep(j, lv.size())if (!e[j]) {
				if (abs(lv[j].a - nw[i]) < eps) {
					vp.push_back(lv[j].b);
				}
				if (abs(lv[j].b - nw[i]) < eps) {
					vp.push_back(lv[j].a);
				}
			}
			//assert(vp.size()==2)
			if (isis_sp({ vp[0],vp[1] }, nw[i])) {

			}
			else {
				anscnt++;
			}
		}
		//cout << i << " " << j << " " << anscnt << " " << anslen << "\n";
		if (macnt < anscnt) {
			macnt = anscnt;
			malen = anslen;
		}
		else if (macnt == anscnt) {
			malen = max(malen, anslen);
		}
	}
	//cout << macnt << " ";
	cout << malen << "\n";
}



signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	//init_f();
	//init();
	//int t; cin >> t; rep(i, t)
	while (cin >> n, n)
		solve();
	return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 3588
final_rank: 7

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS2 0.000000001
using namespace std;


#define EPS 0.00001
#define EPS2 0.0000000001
#define EPS3 0.000001


struct Point{
	Point(long double arg_x,long double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 * (long double a){ return Point(a*x,a*y); }
	Point operator / (long double a){ return Point(x/a,y/a); }

	long double abs(){ return sqrt(norm()); }
	long 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) < EPS2 && fabs(y-p.y) < EPS2;
	}

	/*void debug(){

		printf("(%.3Lf,%.3Lf)\n",x,y);
	}*/
	long double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	long double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
long double NUM = BIG_NUM;


long double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(long double x1,long double y1,long double x2, long double y2, long double xp, long double yp){
	long double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS2){
		return 1;
	}else if(gaiseki < -EPS2){
		return -1;
	}
	if(naiseki < -EPS2){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

long double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS2){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS2){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(long double x1,long double x2,long double x3,long double x4,long double y1,long double y2,long double y3,long double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

long double abs(Vector a){
	return sqrt(norm(a));
}

long double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

long double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

long double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
long double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
long double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
long double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS2){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS2){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS2){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS2){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(long double x1,long double y1,long double x2,long double y2,long double xp,long double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	long double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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) > EPS2)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS2)return CLOCKWISE;
	if(dot(a,b) < -EPS2)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

void  func(){

	Polygon P;

	long double x,y;

	for(int i = 0; i < N; i++){

		scanf("%Lf %Lf",&x,&y);
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	long double ans = 0;

	long double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS2){ //垂直

				long double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS2){ //水平

				long double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			//from側がnear_from
			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //★fromから見て反時計回りで近い方なら(from+i)%N★

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}

			A.clear();
			B.clear();

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 1; b < final_B.size()-1; b++){
					if(isSame(final_A[a],final_B[b])){

						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 1; a < final_A.size()-1; a++){
					if(isSame(final_B[b],final_A[a])){

						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			long double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			long double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				long double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				long double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){ //★★nan対策★★

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/M_PI);
				}
				if(fabs(cos_B+1.0) < EPS2){ //★★nan対策★★

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/M_PI);
				}

				//時計回りの位置関係なら別途計算
				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					deg_B = 360.0-deg_B;
				}

				if(deg_A > deg_B){

					if(fabs(deg_A-180.0) < EPS3){ //同一直線上
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{


					if(fabs(deg_B-180.0) < EPS3){ //同一直線上
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(isSame(cross_point[0],cross_point[1]))tmp_num--; //★★★★★★コーナーケースあり★★★★★★

			if(tmp_num < num_max)continue;

			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	printf("%.15Lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 3256
final_rank: 1

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS2 0.000000001
using namespace std;


#define EPS 0.00001
#define EPS2 0.0000000001
#define EPS3 0.000001


struct Point{
	Point(long double arg_x,long double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 * (long double a){ return Point(a*x,a*y); }
	Point operator / (long double a){ return Point(x/a,y/a); }

	long double abs(){ return sqrt(norm()); }
	long 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) < EPS2 && fabs(y-p.y) < EPS2;
	}

	void debug(){

		printf("(%.3Lf,%.3Lf)\n",x,y);
	}
	long double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	long double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
long double NUM = BIG_NUM;


long double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(long double x1,long double y1,long double x2, long double y2, long double xp, long double yp){
	long double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS2){
		return 1;
	}else if(gaiseki < -EPS2){
		return -1;
	}
	if(naiseki < -EPS2){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

long double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS2){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS2){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(long double x1,long double x2,long double x3,long double x4,long double y1,long double y2,long double y3,long double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

long double abs(Vector a){
	return sqrt(norm(a));
}

long double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

long double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

long double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
long double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
long double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
long double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS2){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS2){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS2){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS2){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(long double x1,long double y1,long double x2,long double y2,long double xp,long double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	long double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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) > EPS2)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS2)return CLOCKWISE;
	if(dot(a,b) < -EPS2)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

void  func(){

	Polygon P;

	long double x,y;

	for(int i = 0; i < N; i++){

		scanf("%Lf %Lf",&x,&y);
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	long double ans = 0;

	long double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS2){ //垂直

				long double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS2){ //水平

				long double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //反時計回りで近い方

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}



			A.clear();
			B.clear();

			//printf("far1: %d far0:%d\n",far_from[1],far_from[0]);

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				//printf("A[%d]",i+1);
				//A[i+1].debug();
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//printf("\n");

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				//printf("B[%d]",i);
				//ref_p.debug();
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						//printf("Bの追加点:");
						//tmp_cross.debug();
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 1; b < final_B.size()-1; b++){
					if(isSame(final_A[a],final_B[b])){

						//printf("★A重なり:");
						//final_A[a].debug();
						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 1; a < final_A.size()-1; a++){
					if(isSame(final_B[b],final_A[a])){

						//printf("★B重なり:");
						//final_B[b].debug();
						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			long double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			//printf("\n\nfrom:%d to:%d\n",from,to);

			//printf("match_A.size():%lld\n",match_A.size());

			long double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				long double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				long double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/M_PI);
				}
				if(fabs(cos_B+1.0) < EPS2){

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/M_PI);
				}


				//printf("i:%d\n",i);

				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					//printf("Aは時計回り\n");
					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					//printf("Bは時計回り\n");
					deg_B = 360.0-deg_B;
				}

				//printf("deg_A:%.3lf deg_B:%.3lf\n",deg_A,deg_B);

				if(deg_A > deg_B){

					//printf("Aの方が大きい\n");

					if(fabs(deg_A-180.0) < EPS3){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						//printf("追加点:");
						//final_A[k].debug();
						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{

					//printf("Bの方が大きい\n");

					if(fabs(deg_B-180.0) < EPS3){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						//printf("追加点:");
						//final_B[k].debug();
						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(isSame(cross_point[0],cross_point[1]))tmp_num--;

			if(tmp_num < num_max)continue;

		/*	printf("\nfrom:%d to:%d\n",from,to);

			printf("交点0:");
			cross_point[0].debug();
			printf("交点1:");
			cross_point[1].debug();

			for(int i = 0; i < 2; i++){

				printf("near[%d]:%d far:%d\n",i,near_from[i],far_from[i]);
			}

			printf("\nポリゴン とどまる\n");
			for(int i = 0; i < A.size(); i++){

				A[i].debug();
			}

			printf("\nポリゴん 動く\n");
			for(int i= 0; i < B.size(); i++){

				B[i].debug();
			}*/

			//printf("from:%d to:%d tmp_num:%d tmp_dist:%.3Lf\n",from,to,tmp_num,tmp_dist);

			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	//printf("num_max:%d\n",num_max);

	printf("%.15Lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 3308
final_rank: 2

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS2 0.000000001
using namespace std;


#define EPS 0.0001
#define EPS2 0.0000000001



struct Point{
	Point(long double arg_x,long double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 * (long double a){ return Point(a*x,a*y); }
	Point operator / (long double a){ return Point(x/a,y/a); }

	long double abs(){ return sqrt(norm()); }
	long 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) < EPS2 && fabs(y-p.y) < EPS2;
	}

	/*void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/
	long double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	long double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
long double NUM = BIG_NUM;


long double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(long double x1,long double y1,long double x2, long double y2, long double xp, long double yp){
	long double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS2){
		return 1;
	}else if(gaiseki < -EPS2){
		return -1;
	}
	if(naiseki < -EPS2){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

long double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS2){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS2){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(long double x1,long double x2,long double x3,long double x4,long double y1,long double y2,long double y3,long double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

long double abs(Vector a){
	return sqrt(norm(a));
}

long double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

long double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

long double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
long double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
long double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
long double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS2){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS2){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS2){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS2){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(long double x1,long double y1,long double x2,long double y2,long double xp,long double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	long double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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) > EPS2)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS2)return CLOCKWISE;
	if(dot(a,b) < -EPS2)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

void  func(){

	Polygon P;

	long double x,y;

	for(int i = 0; i < N; i++){

		scanf("%Lf %Lf",&x,&y);
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	long double ans = 0;

	long double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS2){ //垂直

				long double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS2){ //水平

				long double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //反時計回りで近い方

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}



			A.clear();
			B.clear();

			//printf("far1: %d far0:%d\n",far_from[1],far_from[0]);

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				//printf("A[%d]",i+1);
				//A[i+1].debug();
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//printf("\n");

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				//printf("B[%d]",i);
				//ref_p.debug();
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						//printf("Bの追加点:");
						//tmp_cross.debug();
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 0; b < final_B.size(); b++){
					if(isSame(final_A[a],final_B[b])){

						//printf("★A重なり:");
						//final_A[a].debug();
						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 0; a < final_A.size(); a++){
					if(isSame(final_B[b],final_A[a])){

						//printf("★B重なり:");
						//final_B[b].debug();
						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			long double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			//printf("\n\nfrom:%d to:%d\n",from,to);

			long double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				long double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				long double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/M_PI);
				}
				if(fabs(cos_B+1.0) < EPS2){

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/M_PI);
				}


				//printf("i:%d\n",i);

				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					//printf("Aは時計回り\n");
					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					//printf("Bは時計回り\n");
					deg_B = 360.0-deg_B;
				}

				//printf("deg_A:%.3lf deg_B:%.3lf\n",deg_A,deg_B);

				if(deg_A > deg_B){

					//printf("Aの方が大きい\n");

					if(fabs(deg_A-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						//printf("追加点:");
						//final_A[k].debug();
						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{

					//printf("Bの方が大きい\n");

					if(fabs(deg_B-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						//printf("追加点:");
						//final_B[k].debug();
						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(tmp_num < num_max)continue;

			/*printf("\nfrom:%d to:%d\n",from,to);

			printf("交点0:");
			cross_point[0].debug();
			printf("交点1:");
			cross_point[1].debug();

			for(int i = 0; i < 2; i++){

				printf("near[%d]:%d far:%d\n",i,near_from[i],far_from[i]);
			}

			printf("\nポリゴン とどまる\n");
			for(int i = 0; i < A.size(); i++){

				A[i].debug();
			}

			printf("\nポリゴん 動く\n");
			for(int i= 0; i < B.size(); i++){

				B[i].debug();
			}*/

			//printf("tmp_num:%d tmp_dist:%.3lf\n",tmp_num,tmp_dist);


			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	//printf("num_max:%d\n",num_max);

	printf("%.15Lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 0.5
time_ms: 30
memory_kb: 3232
final_rank: 11

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS2 0.000000001
using namespace std;


#define EPS 0.0000001
#define EPS2 0.0000000001



struct Point{
	Point(long double arg_x,long double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 * (long double a){ return Point(a*x,a*y); }
	Point operator / (long double a){ return Point(x/a,y/a); }

	long double abs(){ return sqrt(norm()); }
	long 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) < EPS2 && fabs(y-p.y) < EPS2;
	}

	/*void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/
	long double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	long double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
long double NUM = BIG_NUM;


long double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(long double x1,long double y1,long double x2, long double y2, long double xp, long double yp){
	long double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS2){
		return 1;
	}else if(gaiseki < -EPS2){
		return -1;
	}
	if(naiseki < -EPS2){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

long double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS2){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS2){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(long double x1,long double x2,long double x3,long double x4,long double y1,long double y2,long double y3,long double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

long double abs(Vector a){
	return sqrt(norm(a));
}

long double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

long double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

long double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
long double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
long double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
long double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS2){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS2){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS2){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS2){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(long double x1,long double y1,long double x2,long double y2,long double xp,long double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	long double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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) > EPS2)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS2)return CLOCKWISE;
	if(dot(a,b) < -EPS2)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

void  func(){

	Polygon P;

	long double x,y;

	for(int i = 0; i < N; i++){

		scanf("%Lf %Lf",&x,&y);
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	long double ans = 0;

	long double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS2){ //垂直

				long double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS2){ //水平

				long double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //反時計回りで近い方

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}



			A.clear();
			B.clear();

			//printf("far1: %d far0:%d\n",far_from[1],far_from[0]);

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				//printf("A[%d]",i+1);
				//A[i+1].debug();
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//printf("\n");

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				//printf("B[%d]",i);
				//ref_p.debug();
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						//printf("Bの追加点:");
						//tmp_cross.debug();
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 0; b < final_B.size(); b++){
					if(isSame(final_A[a],final_B[b])){

						//printf("★A重なり:");
						//final_A[a].debug();
						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 0; a < final_A.size(); a++){
					if(isSame(final_B[b],final_A[a])){

						//printf("★B重なり:");
						//final_B[b].debug();
						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			long double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			//printf("\n\nfrom:%d to:%d\n",from,to);

			long double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				long double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				long double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/M_PI);
				}
				if(fabs(cos_B+1.0) < EPS2){

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/M_PI);
				}


				//printf("i:%d\n",i);

				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					//printf("Aは時計回り\n");
					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					//printf("Bは時計回り\n");
					deg_B = 360.0-deg_B;
				}

				//printf("deg_A:%.3lf deg_B:%.3lf\n",deg_A,deg_B);

				if(deg_A > deg_B){

					//printf("Aの方が大きい\n");

					if(fabs(deg_A-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						//printf("追加点:");
						//final_A[k].debug();
						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{

					//printf("Bの方が大きい\n");

					if(fabs(deg_B-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						//printf("追加点:");
						//final_B[k].debug();
						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(tmp_num < num_max)continue;

			/*printf("\nfrom:%d to:%d\n",from,to);

			printf("交点0:");
			cross_point[0].debug();
			printf("交点1:");
			cross_point[1].debug();

			for(int i = 0; i < 2; i++){

				printf("near[%d]:%d far:%d\n",i,near_from[i],far_from[i]);
			}

			printf("\nポリゴン とどまる\n");
			for(int i = 0; i < A.size(); i++){

				A[i].debug();
			}

			printf("\nポリゴん 動く\n");
			for(int i= 0; i < B.size(); i++){

				B[i].debug();
			}*/

			//printf("tmp_num:%d tmp_dist:%.3lf\n",tmp_num,tmp_dist);


			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	//printf("num_max:%d\n",num_max);

	printf("%.15Lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 0.5
time_ms: 30
memory_kb: 3180
final_rank: 9

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS2 0.000000001
using namespace std;


#define EPS 0.000001
#define EPS2 0.0000000001



struct Point{
	Point(long double arg_x,long double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 * (long double a){ return Point(a*x,a*y); }
	Point operator / (long double a){ return Point(x/a,y/a); }

	long double abs(){ return sqrt(norm()); }
	long 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) < EPS2 && fabs(y-p.y) < EPS2;
	}

	/*void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/
	long double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	long double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
long double NUM = BIG_NUM;


long double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(long double x1,long double y1,long double x2, long double y2, long double xp, long double yp){
	long double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS2){
		return 1;
	}else if(gaiseki < -EPS2){
		return -1;
	}
	if(naiseki < -EPS2){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

long double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS2){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS2){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(long double x1,long double x2,long double x3,long double x4,long double y1,long double y2,long double y3,long double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

long double abs(Vector a){
	return sqrt(norm(a));
}

long double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

long double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

long double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
long double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
long double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
long double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS2){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS2){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS2){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS2){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(long double x1,long double y1,long double x2,long double y2,long double xp,long double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	long double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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) > EPS2)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS2)return CLOCKWISE;
	if(dot(a,b) < -EPS2)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

void  func(){

	Polygon P;

	long double x,y;

	for(int i = 0; i < N; i++){

		scanf("%Lf %Lf",&x,&y);
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	long double ans = 0;

	long double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS2){ //垂直

				long double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS2){ //水平

				long double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //反時計回りで近い方

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}



			A.clear();
			B.clear();

			//printf("far1: %d far0:%d\n",far_from[1],far_from[0]);

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				//printf("A[%d]",i+1);
				//A[i+1].debug();
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//printf("\n");

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				//printf("B[%d]",i);
				//ref_p.debug();
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						//printf("Bの追加点:");
						//tmp_cross.debug();
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 0; b < final_B.size(); b++){
					if(isSame(final_A[a],final_B[b])){

						//printf("★A重なり:");
						//final_A[a].debug();
						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 0; a < final_A.size(); a++){
					if(isSame(final_B[b],final_A[a])){

						//printf("★B重なり:");
						//final_B[b].debug();
						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			long double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			//printf("\n\nfrom:%d to:%d\n",from,to);

			long double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				long double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				long double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/M_PI);
				}
				if(fabs(cos_B+1.0) < EPS2){

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/M_PI);
				}


				//printf("i:%d\n",i);

				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					//printf("Aは時計回り\n");
					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					//printf("Bは時計回り\n");
					deg_B = 360.0-deg_B;
				}

				//printf("deg_A:%.3lf deg_B:%.3lf\n",deg_A,deg_B);

				if(deg_A > deg_B){

					//printf("Aの方が大きい\n");

					if(fabs(deg_A-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						//printf("追加点:");
						//final_A[k].debug();
						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{

					//printf("Bの方が大きい\n");

					if(fabs(deg_B-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						//printf("追加点:");
						//final_B[k].debug();
						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(tmp_num < num_max)continue;

			/*printf("\nfrom:%d to:%d\n",from,to);

			printf("交点0:");
			cross_point[0].debug();
			printf("交点1:");
			cross_point[1].debug();

			for(int i = 0; i < 2; i++){

				printf("near[%d]:%d far:%d\n",i,near_from[i],far_from[i]);
			}

			printf("\nポリゴン とどまる\n");
			for(int i = 0; i < A.size(); i++){

				A[i].debug();
			}

			printf("\nポリゴん 動く\n");
			for(int i= 0; i < B.size(); i++){

				B[i].debug();
			}*/

			//printf("tmp_num:%d tmp_dist:%.3lf\n",tmp_num,tmp_dist);


			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	//printf("num_max:%d\n",num_max);

	printf("%.15Lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 0.5
time_ms: 30
memory_kb: 3224
final_rank: 10

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS2 0.000000001
using namespace std;


#define EPS 0.00001
#define EPS2 0.0000000001



struct Point{
	Point(long double arg_x,long double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 * (long double a){ return Point(a*x,a*y); }
	Point operator / (long double a){ return Point(x/a,y/a); }

	long double abs(){ return sqrt(norm()); }
	long 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) < EPS2 && fabs(y-p.y) < EPS2;
	}

	/*void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/
	long double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	long double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
long double NUM = BIG_NUM;


long double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(long double x1,long double y1,long double x2, long double y2, long double xp, long double yp){
	long double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS2){
		return 1;
	}else if(gaiseki < -EPS2){
		return -1;
	}
	if(naiseki < -EPS2){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

long double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS2){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS2){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(long double x1,long double x2,long double x3,long double x4,long double y1,long double y2,long double y3,long double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

long double abs(Vector a){
	return sqrt(norm(a));
}

long double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

long double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

long double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
long double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
long double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
long double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS2){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS2){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS2){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS2){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(long double x1,long double y1,long double x2,long double y2,long double xp,long double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	long double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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) > EPS2)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS2)return CLOCKWISE;
	if(dot(a,b) < -EPS2)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

void  func(){

	Polygon P;

	long double x,y;

	for(int i = 0; i < N; i++){

		scanf("%Lf %Lf",&x,&y);
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	long double ans = 0;

	long double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS2){ //垂直

				long double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS2){ //水平

				long double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //反時計回りで近い方

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}



			A.clear();
			B.clear();

			//printf("far1: %d far0:%d\n",far_from[1],far_from[0]);

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				//printf("A[%d]",i+1);
				//A[i+1].debug();
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//printf("\n");

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				//printf("B[%d]",i);
				//ref_p.debug();
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						//printf("Bの追加点:");
						//tmp_cross.debug();
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 0; b < final_B.size(); b++){
					if(isSame(final_A[a],final_B[b])){

						//printf("★A重なり:");
						//final_A[a].debug();
						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 0; a < final_A.size(); a++){
					if(isSame(final_B[b],final_A[a])){

						//printf("★B重なり:");
						//final_B[b].debug();
						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			long double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			//printf("\n\nfrom:%d to:%d\n",from,to);

			long double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				long double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				long double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/M_PI);
				}
				if(fabs(cos_B+1.0) < EPS2){

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/M_PI);
				}


				//printf("i:%d\n",i);

				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					//printf("Aは時計回り\n");
					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					//printf("Bは時計回り\n");
					deg_B = 360.0-deg_B;
				}

				//printf("deg_A:%.3lf deg_B:%.3lf\n",deg_A,deg_B);

				if(deg_A > deg_B){

					//printf("Aの方が大きい\n");

					if(fabs(deg_A-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						//printf("追加点:");
						//final_A[k].debug();
						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{

					//printf("Bの方が大きい\n");

					if(fabs(deg_B-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						//printf("追加点:");
						//final_B[k].debug();
						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(tmp_num < num_max)continue;

			/*printf("\nfrom:%d to:%d\n",from,to);

			printf("交点0:");
			cross_point[0].debug();
			printf("交点1:");
			cross_point[1].debug();

			for(int i = 0; i < 2; i++){

				printf("near[%d]:%d far:%d\n",i,near_from[i],far_from[i]);
			}

			printf("\nポリゴン とどまる\n");
			for(int i = 0; i < A.size(); i++){

				A[i].debug();
			}

			printf("\nポリゴん 動く\n");
			for(int i= 0; i < B.size(); i++){

				B[i].debug();
			}*/

			//printf("tmp_num:%d tmp_dist:%.3lf\n",tmp_num,tmp_dist);


			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	//printf("num_max:%d\n",num_max);

	printf("%.15Lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 0.5
time_ms: 30
memory_kb: 3236
final_rank: 12

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS2 0.000000001
using namespace std;


#define EPS 0.000000001
#define EPS2 0.000000001



struct Point{
	Point(long double arg_x,long double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 * (long double a){ return Point(a*x,a*y); }
	Point operator / (long double a){ return Point(x/a,y/a); }

	long double abs(){ return sqrt(norm()); }
	long 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) < EPS2 && fabs(y-p.y) < EPS2;
	}

	/*void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/
	long double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	long double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
long double NUM = BIG_NUM;


long double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(long double x1,long double y1,long double x2, long double y2, long double xp, long double yp){
	long double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS2){
		return 1;
	}else if(gaiseki < -EPS2){
		return -1;
	}
	if(naiseki < -EPS2){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

long double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS2){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS2){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(long double x1,long double x2,long double x3,long double x4,long double y1,long double y2,long double y3,long double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

long double abs(Vector a){
	return sqrt(norm(a));
}

long double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

long double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

long double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
long double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
long double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
long double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS2){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS2){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS2){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS2){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(long double x1,long double y1,long double x2,long double y2,long double xp,long double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	long double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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) > EPS2)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS2)return CLOCKWISE;
	if(dot(a,b) < -EPS2)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

void  func(){

	Polygon P;

	long double x,y;

	for(int i = 0; i < N; i++){

		scanf("%Lf %Lf",&x,&y);
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	long double ans = 0;

	long double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS2){ //垂直

				long double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS2){ //水平

				long double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //反時計回りで近い方

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}



			A.clear();
			B.clear();

			//printf("far1: %d far0:%d\n",far_from[1],far_from[0]);

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				//printf("A[%d]",i+1);
				//A[i+1].debug();
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//printf("\n");

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				//printf("B[%d]",i);
				//ref_p.debug();
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						//printf("Bの追加点:");
						//tmp_cross.debug();
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 0; b < final_B.size(); b++){
					if(isSame(final_A[a],final_B[b])){

						//printf("★A重なり:");
						//final_A[a].debug();
						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 0; a < final_A.size(); a++){
					if(isSame(final_B[b],final_A[a])){

						//printf("★B重なり:");
						//final_B[b].debug();
						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			long double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			//printf("\n\nfrom:%d to:%d\n",from,to);

			long double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				long double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				long double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/M_PI);
				}
				if(fabs(cos_B+1.0) < EPS2){

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/M_PI);
				}


				//printf("i:%d\n",i);

				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					//printf("Aは時計回り\n");
					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					//printf("Bは時計回り\n");
					deg_B = 360.0-deg_B;
				}

				//printf("deg_A:%.3lf deg_B:%.3lf\n",deg_A,deg_B);

				if(deg_A > deg_B){

					//printf("Aの方が大きい\n");

					if(fabs(deg_A-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						//printf("追加点:");
						//final_A[k].debug();
						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{

					//printf("Bの方が大きい\n");

					if(fabs(deg_B-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						//printf("追加点:");
						//final_B[k].debug();
						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(tmp_num < num_max)continue;

			/*printf("\nfrom:%d to:%d\n",from,to);

			printf("交点0:");
			cross_point[0].debug();
			printf("交点1:");
			cross_point[1].debug();

			for(int i = 0; i < 2; i++){

				printf("near[%d]:%d far:%d\n",i,near_from[i],far_from[i]);
			}

			printf("\nポリゴン とどまる\n");
			for(int i = 0; i < A.size(); i++){

				A[i].debug();
			}

			printf("\nポリゴん 動く\n");
			for(int i= 0; i < B.size(); i++){

				B[i].debug();
			}*/

			//printf("tmp_num:%d tmp_dist:%.3lf\n",tmp_num,tmp_dist);


			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	//printf("num_max:%d\n",num_max);

	printf("%.15Lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 0.5
time_ms: 30
memory_kb: 3348
final_rank: 18

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS2 0.000000001
using namespace std;


#define EPS 0.00001
#define EPS2 0.000000001



struct Point{
	Point(long double arg_x,long double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 * (long double a){ return Point(a*x,a*y); }
	Point operator / (long double a){ return Point(x/a,y/a); }

	long double abs(){ return sqrt(norm()); }
	long 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) < EPS2 && fabs(y-p.y) < EPS2;
	}

	/*void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/
	long double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	long double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
long double NUM = BIG_NUM;


long double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(long double x1,long double y1,long double x2, long double y2, long double xp, long double yp){
	long double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS2){
		return 1;
	}else if(gaiseki < -EPS2){
		return -1;
	}
	if(naiseki < -EPS2){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

long double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS2){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS2){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(long double x1,long double x2,long double x3,long double x4,long double y1,long double y2,long double y3,long double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

long double abs(Vector a){
	return sqrt(norm(a));
}

long double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

long double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

long double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
long double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
long double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
long double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS2){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS2){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS2){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS2){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(long double x1,long double y1,long double x2,long double y2,long double xp,long double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	long double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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) > EPS2)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS2)return CLOCKWISE;
	if(dot(a,b) < -EPS2)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

void  func(){

	Polygon P;

	long double x,y;

	for(int i = 0; i < N; i++){

		scanf("%Lf %Lf",&x,&y);
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	long double ans = 0;

	long double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS2){ //垂直

				long double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS2){ //水平

				long double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //反時計回りで近い方

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}



			A.clear();
			B.clear();

			//printf("far1: %d far0:%d\n",far_from[1],far_from[0]);

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				//printf("A[%d]",i+1);
				//A[i+1].debug();
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//printf("\n");

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				//printf("B[%d]",i);
				//ref_p.debug();
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						//printf("Bの追加点:");
						//tmp_cross.debug();
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 0; b < final_B.size(); b++){
					if(isSame(final_A[a],final_B[b])){

						//printf("★A重なり:");
						//final_A[a].debug();
						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 0; a < final_A.size(); a++){
					if(isSame(final_B[b],final_A[a])){

						//printf("★B重なり:");
						//final_B[b].debug();
						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			long double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			//printf("\n\nfrom:%d to:%d\n",from,to);

			long double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				long double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				long double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/M_PI);
				}
				if(fabs(cos_B+1.0) < EPS2){

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/M_PI);
				}


				//printf("i:%d\n",i);

				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					//printf("Aは時計回り\n");
					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					//printf("Bは時計回り\n");
					deg_B = 360.0-deg_B;
				}

				//printf("deg_A:%.3lf deg_B:%.3lf\n",deg_A,deg_B);

				if(deg_A > deg_B){

					//printf("Aの方が大きい\n");

					if(fabs(deg_A-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						//printf("追加点:");
						//final_A[k].debug();
						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{

					//printf("Bの方が大きい\n");

					if(fabs(deg_B-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						//printf("追加点:");
						//final_B[k].debug();
						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(tmp_num < num_max)continue;

			/*printf("\nfrom:%d to:%d\n",from,to);

			printf("交点0:");
			cross_point[0].debug();
			printf("交点1:");
			cross_point[1].debug();

			for(int i = 0; i < 2; i++){

				printf("near[%d]:%d far:%d\n",i,near_from[i],far_from[i]);
			}

			printf("\nポリゴン とどまる\n");
			for(int i = 0; i < A.size(); i++){

				A[i].debug();
			}

			printf("\nポリゴん 動く\n");
			for(int i= 0; i < B.size(); i++){

				B[i].debug();
			}*/

			//printf("tmp_num:%d tmp_dist:%.3lf\n",tmp_num,tmp_dist);


			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	//printf("num_max:%d\n",num_max);

	printf("%.15Lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 0.5
time_ms: 30
memory_kb: 3136
final_rank: 8

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS 0.000000001
using namespace std;



#define EPS 0.00001
#define EPS2  0.000000001


struct Point{
	Point(long double arg_x,long double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 * (long double a){ return Point(a*x,a*y); }
	Point operator / (long double a){ return Point(x/a,y/a); }

	long double abs(){ return sqrt(norm()); }
	long 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;
	}

	/*void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/
	long double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	long double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
long double NUM = BIG_NUM;


long double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(long double x1,long double y1,long double x2, long double y2, long double xp, long double yp){
	long double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

long double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(long double x1,long double x2,long double x3,long double x4,long double y1,long double y2,long double y3,long double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

long double abs(Vector a){
	return sqrt(norm(a));
}

long double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

long double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

long double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
long double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
long double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
long double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(long double x1,long double y1,long double x2,long double y2,long double xp,long double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	long double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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;
}

void  func(){

	Polygon P;

	long double x,y;

	for(int i = 0; i < N; i++){

		scanf("%Lf %Lf",&x,&y);
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	long double ans = 0;

	long double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS){ //垂直

				long double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS){ //水平

				long double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //反時計回りで近い方

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}



			A.clear();
			B.clear();

			//printf("far1: %d far0:%d\n",far_from[1],far_from[0]);

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				//printf("A[%d]",i+1);
				//A[i+1].debug();
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//printf("\n");

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				//printf("B[%d]",i);
				//ref_p.debug();
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						//printf("Bの追加点:");
						//tmp_cross.debug();
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 0; b < final_B.size(); b++){
					if(isSame(final_A[a],final_B[b])){

						//printf("★A重なり:");
						//final_A[a].debug();
						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 0; a < final_A.size(); a++){
					if(isSame(final_B[b],final_A[a])){

						//printf("★B重なり:");
						//final_B[b].debug();
						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			long double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			//printf("\n\nfrom:%d to:%d\n",from,to);

			long double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				long double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				long double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/M_PI);
				}
				if(fabs(cos_B+1.0) < EPS2){

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/M_PI);
				}


				//printf("i:%d\n",i);

				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					//printf("Aは時計回り\n");
					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					//printf("Bは時計回り\n");
					deg_B = 360.0-deg_B;
				}

				//printf("deg_A:%.3lf deg_B:%.3lf\n",deg_A,deg_B);

				if(deg_A > deg_B){

					//printf("Aの方が大きい\n");

					if(fabs(deg_A-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						//printf("追加点:");
						//final_A[k].debug();
						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{

					//printf("Bの方が大きい\n");

					if(fabs(deg_B-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						//printf("追加点:");
						//final_B[k].debug();
						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(tmp_num < num_max)continue;

			/*printf("\nfrom:%d to:%d\n",from,to);

			printf("交点0:");
			cross_point[0].debug();
			printf("交点1:");
			cross_point[1].debug();

			for(int i = 0; i < 2; i++){

				printf("near[%d]:%d far:%d\n",i,near_from[i],far_from[i]);
			}

			printf("\nポリゴン とどまる\n");
			for(int i = 0; i < A.size(); i++){

				A[i].debug();
			}

			printf("\nポリゴん 動く\n");
			for(int i= 0; i < B.size(); i++){

				B[i].debug();
			}*/

			//printf("tmp_num:%d tmp_dist:%.3lf\n",tmp_num,tmp_dist);


			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	//printf("num_max:%d\n",num_max);

	printf("%.15Lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 0.5
time_ms: 30
memory_kb: 3316
final_rank: 16

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS 0.000000001
using namespace std;



#define EPS 0.00001
#define EPS2  0.000000001


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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); }

	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;
	}

	/*void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/
	double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
double NUM = BIG_NUM;


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

double abs(Vector a){
	return sqrt(norm(a));
}

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

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

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(double x1,double y1,double x2,double y2,double xp,double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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;
}

void  func(){

	Polygon P;

	double x,y;

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&x,&y);
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	double ans = 0;

	double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS){ //垂直

				double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS){ //水平

				double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //反時計回りで近い方

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}



			A.clear();
			B.clear();

			//printf("far1: %d far0:%d\n",far_from[1],far_from[0]);

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				//printf("A[%d]",i+1);
				//A[i+1].debug();
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//printf("\n");

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				//printf("B[%d]",i);
				//ref_p.debug();
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						//printf("Bの追加点:");
						//tmp_cross.debug();
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 0; b < final_B.size(); b++){
					if(isSame(final_A[a],final_B[b])){

						//printf("★A重なり:");
						//final_A[a].debug();
						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 0; a < final_A.size(); a++){
					if(isSame(final_B[b],final_A[a])){

						//printf("★B重なり:");
						//final_B[b].debug();
						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			//printf("\n\nfrom:%d to:%d\n",from,to);

			double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/M_PI);
				}
				if(fabs(cos_B+1.0) < EPS2){

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/M_PI);
				}


				//printf("i:%d\n",i);

				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					//printf("Aは時計回り\n");
					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					//printf("Bは時計回り\n");
					deg_B = 360.0-deg_B;
				}

				//printf("deg_A:%.3lf deg_B:%.3lf\n",deg_A,deg_B);

				if(deg_A > deg_B){

					//printf("Aの方が大きい\n");

					if(fabs(deg_A-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						//printf("追加点:");
						//final_A[k].debug();
						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{

					//printf("Bの方が大きい\n");

					if(fabs(deg_B-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						//printf("追加点:");
						//final_B[k].debug();
						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(tmp_num < num_max)continue;

			/*printf("\nfrom:%d to:%d\n",from,to);

			printf("交点0:");
			cross_point[0].debug();
			printf("交点1:");
			cross_point[1].debug();

			for(int i = 0; i < 2; i++){

				printf("near[%d]:%d far:%d\n",i,near_from[i],far_from[i]);
			}

			printf("\nポリゴン とどまる\n");
			for(int i = 0; i < A.size(); i++){

				A[i].debug();
			}

			printf("\nポリゴん 動く\n");
			for(int i= 0; i < B.size(); i++){

				B[i].debug();
			}*/

			//printf("tmp_num:%d tmp_dist:%.3lf\n",tmp_num,tmp_dist);


			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	//printf("num_max:%d\n",num_max);

	printf("%.15lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 0.5
time_ms: 10
memory_kb: 3476
final_rank: 20

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS 0.000000001
using namespace std;



#define EPS 0.00000001
#define EPS2  0.000000001


struct Point{
	Point(long double arg_x,long double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 * (long double a){ return Point(a*x,a*y); }
	Point operator / (long double a){ return Point(x/a,y/a); }

	long double abs(){ return sqrt(norm()); }
	long 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;
	}

	/*void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/
	long double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	long double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
long double NUM = BIG_NUM;


long double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(long double x1,long double y1,long double x2, long double y2, long double xp, long double yp){
	long double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

long double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(long double x1,long double x2,long double x3,long double x4,long double y1,long double y2,long double y3,long double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

long double abs(Vector a){
	return sqrt(norm(a));
}

long double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

long double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

long double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
long double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
long double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
long double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(long double x1,long double y1,long double x2,long double y2,long double xp,long double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	long double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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;
}

void  func(){

	Polygon P;

	long double x,y;

	for(int i = 0; i < N; i++){

		scanf("%Lf %Lf",&x,&y);
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	long double ans = 0;

	long double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS){ //垂直

				long double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS){ //水平

				long double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //反時計回りで近い方

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}



			A.clear();
			B.clear();

			//printf("far1: %d far0:%d\n",far_from[1],far_from[0]);

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				//printf("A[%d]",i+1);
				//A[i+1].debug();
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//printf("\n");

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				//printf("B[%d]",i);
				//ref_p.debug();
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						//printf("Bの追加点:");
						//tmp_cross.debug();
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 0; b < final_B.size(); b++){
					if(isSame(final_A[a],final_B[b])){

						//printf("★A重なり:");
						//final_A[a].debug();
						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 0; a < final_A.size(); a++){
					if(isSame(final_B[b],final_A[a])){

						//printf("★B重なり:");
						//final_B[b].debug();
						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			long double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			//printf("\n\nfrom:%d to:%d\n",from,to);

			long double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				long double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				long double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/M_PI);
				}
				if(fabs(cos_B+1.0) < EPS2){

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/M_PI);
				}


				//printf("i:%d\n",i);

				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					//printf("Aは時計回り\n");
					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					//printf("Bは時計回り\n");
					deg_B = 360.0-deg_B;
				}

				//printf("deg_A:%.3lf deg_B:%.3lf\n",deg_A,deg_B);

				if(deg_A > deg_B){

					//printf("Aの方が大きい\n");

					if(fabs(deg_A-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						//printf("追加点:");
						//final_A[k].debug();
						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{

					//printf("Bの方が大きい\n");

					if(fabs(deg_B-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						//printf("追加点:");
						//final_B[k].debug();
						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(tmp_num < num_max)continue;

			/*printf("\nfrom:%d to:%d\n",from,to);

			printf("交点0:");
			cross_point[0].debug();
			printf("交点1:");
			cross_point[1].debug();

			for(int i = 0; i < 2; i++){

				printf("near[%d]:%d far:%d\n",i,near_from[i],far_from[i]);
			}

			printf("\nポリゴン とどまる\n");
			for(int i = 0; i < A.size(); i++){

				A[i].debug();
			}

			printf("\nポリゴん 動く\n");
			for(int i= 0; i < B.size(); i++){

				B[i].debug();
			}*/

			//printf("tmp_num:%d tmp_dist:%.3lf\n",tmp_num,tmp_dist);


			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	//printf("num_max:%d\n",num_max);

	printf("%.15Lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 0.5
time_ms: 30
memory_kb: 3312
final_rank: 15

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS 0.000000001
using namespace std;



#define EPS 0.00001
#define EPS2  0.000000001


struct Point{
	Point(long double arg_x,long double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 * (long double a){ return Point(a*x,a*y); }
	Point operator / (long double a){ return Point(x/a,y/a); }

	long double abs(){ return sqrt(norm()); }
	long 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;
	}

	/*void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/
	long double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	long double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
long double NUM = BIG_NUM;


long double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(long double x1,long double y1,long double x2, long double y2, long double xp, long double yp){
	long double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

long double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(long double x1,long double x2,long double x3,long double x4,long double y1,long double y2,long double y3,long double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

long double abs(Vector a){
	return sqrt(norm(a));
}

long double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

long double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

long double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
long double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
long double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
long double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(long double x1,long double y1,long double x2,long double y2,long double xp,long double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	long double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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;
}

void  func(){

	Polygon P;

	long double x,y;

	for(int i = 0; i < N; i++){

		scanf("%Lf %Lf",&x,&y);
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	long double ans = 0;

	long double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS){ //垂直

				long double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS){ //水平

				long double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //反時計回りで近い方

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}



			A.clear();
			B.clear();

			//printf("far1: %d far0:%d\n",far_from[1],far_from[0]);

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				//printf("A[%d]",i+1);
				//A[i+1].debug();
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//printf("\n");

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				//printf("B[%d]",i);
				//ref_p.debug();
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						//printf("Bの追加点:");
						//tmp_cross.debug();
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 0; b < final_B.size(); b++){
					if(isSame(final_A[a],final_B[b])){

						//printf("★A重なり:");
						//final_A[a].debug();
						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 0; a < final_A.size(); a++){
					if(isSame(final_B[b],final_A[a])){

						//printf("★B重なり:");
						//final_B[b].debug();
						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			long double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			//printf("\n\nfrom:%d to:%d\n",from,to);

			long double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				long double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				long double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/acos(-1));
				}
				if(fabs(cos_B+1.0) < EPS2){

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/acos(-1));
				}


				//printf("i:%d\n",i);

				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					//printf("Aは時計回り\n");
					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					//printf("Bは時計回り\n");
					deg_B = 360.0-deg_B;
				}

				//printf("deg_A:%.3lf deg_B:%.3lf\n",deg_A,deg_B);

				if(deg_A > deg_B){

					//printf("Aの方が大きい\n");

					if(fabs(deg_A-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						//printf("追加点:");
						//final_A[k].debug();
						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{

					//printf("Bの方が大きい\n");

					if(fabs(deg_B-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						//printf("追加点:");
						//final_B[k].debug();
						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(tmp_num < num_max)continue;

			/*printf("\nfrom:%d to:%d\n",from,to);

			printf("交点0:");
			cross_point[0].debug();
			printf("交点1:");
			cross_point[1].debug();

			for(int i = 0; i < 2; i++){

				printf("near[%d]:%d far:%d\n",i,near_from[i],far_from[i]);
			}

			printf("\nポリゴン とどまる\n");
			for(int i = 0; i < A.size(); i++){

				A[i].debug();
			}

			printf("\nポリゴん 動く\n");
			for(int i= 0; i < B.size(); i++){

				B[i].debug();
			}*/

			//printf("tmp_num:%d tmp_dist:%.3lf\n",tmp_num,tmp_dist);


			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	//printf("num_max:%d\n",num_max);

	printf("%.15Lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 0.5
time_ms: 30
memory_kb: 3264
final_rank: 14

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS 0.000000001
using namespace std;



#define EPS 0.00001
#define EPS2  0.000000001


struct Point{
	Point(long double arg_x,long double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 * (long double a){ return Point(a*x,a*y); }
	Point operator / (long double a){ return Point(x/a,y/a); }

	long double abs(){ return sqrt(norm()); }
	long 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;
	}

	/*void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/
	long double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	long double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
long double NUM = BIG_NUM;


long double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(long double x1,long double y1,long double x2, long double y2, long double xp, long double yp){
	long double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

long double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(long double x1,long double x2,long double x3,long double x4,long double y1,long double y2,long double y3,long double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

long double abs(Vector a){
	return sqrt(norm(a));
}

long double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

long double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

long double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
long double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
long double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
long double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(long double x1,long double y1,long double x2,long double y2,long double xp,long double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	long double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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;
}

void  func(){

	Polygon P;

	long double x,y;

	for(int i = 0; i < N; i++){

		//scanf("%Lf %Lf",&x,&y);
		cin >> x >> y;
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	long double ans = 0;

	long double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS){ //垂直

				long double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS){ //水平

				long double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //反時計回りで近い方

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}



			A.clear();
			B.clear();

			//printf("far1: %d far0:%d\n",far_from[1],far_from[0]);

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				//printf("A[%d]",i+1);
				//A[i+1].debug();
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//printf("\n");

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				//printf("B[%d]",i);
				//ref_p.debug();
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						//printf("Bの追加点:");
						//tmp_cross.debug();
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 0; b < final_B.size(); b++){
					if(isSame(final_A[a],final_B[b])){

						//printf("★A重なり:");
						//final_A[a].debug();
						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 0; a < final_A.size(); a++){
					if(isSame(final_B[b],final_A[a])){

						//printf("★B重なり:");
						//final_B[b].debug();
						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			long double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			//printf("\n\nfrom:%d to:%d\n",from,to);

			long double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				long double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				long double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/M_PI);
				}
				if(fabs(cos_B+1.0) < EPS2){

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/M_PI);
				}


				//printf("i:%d\n",i);

				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					//printf("Aは時計回り\n");
					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					//printf("Bは時計回り\n");
					deg_B = 360.0-deg_B;
				}

				//printf("deg_A:%.3lf deg_B:%.3lf\n",deg_A,deg_B);

				if(deg_A > deg_B){

					//printf("Aの方が大きい\n");

					if(fabs(deg_A-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						//printf("追加点:");
						//final_A[k].debug();
						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{

					//printf("Bの方が大きい\n");

					if(fabs(deg_B-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						//printf("追加点:");
						//final_B[k].debug();
						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(tmp_num < num_max)continue;

			/*printf("\nfrom:%d to:%d\n",from,to);

			printf("交点0:");
			cross_point[0].debug();
			printf("交点1:");
			cross_point[1].debug();

			for(int i = 0; i < 2; i++){

				printf("near[%d]:%d far:%d\n",i,near_from[i],far_from[i]);
			}

			printf("\nポリゴン とどまる\n");
			for(int i = 0; i < A.size(); i++){

				A[i].debug();
			}

			printf("\nポリゴん 動く\n");
			for(int i= 0; i < B.size(); i++){

				B[i].debug();
			}*/

			//printf("tmp_num:%d tmp_dist:%.3lf\n",tmp_num,tmp_dist);


			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	//printf("num_max:%d\n",num_max);

	printf("%.15Lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 0.5
time_ms: 30
memory_kb: 3336
final_rank: 17

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS 0.000000001
using namespace std;



#define EPS 0.000001
#define EPS2   0.000001


struct Point{
	Point(long double arg_x,long double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 * (long double a){ return Point(a*x,a*y); }
	Point operator / (long double a){ return Point(x/a,y/a); }

	long double abs(){ return sqrt(norm()); }
	long 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;
	}

	/*void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/
	long double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	long double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
long double NUM = BIG_NUM;


long double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(long double x1,long double y1,long double x2, long double y2, long double xp, long double yp){
	long double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

long double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(long double x1,long double x2,long double x3,long double x4,long double y1,long double y2,long double y3,long double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

long double abs(Vector a){
	return sqrt(norm(a));
}

long double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

long double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

long double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
long double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
long double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
long double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(long double x1,long double y1,long double x2,long double y2,long double xp,long double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	long double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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;
}

void  func(){

	Polygon P;

	long double x,y;

	for(int i = 0; i < N; i++){

		scanf("%Lf %Lf",&x,&y);
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	long double ans = 0;

	long double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS){ //垂直

				long double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS){ //水平

				long double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //反時計回りで近い方

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}



			A.clear();
			B.clear();

			//printf("far1: %d far0:%d\n",far_from[1],far_from[0]);

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				//printf("A[%d]",i+1);
				//A[i+1].debug();
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//printf("\n");

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				//printf("B[%d]",i);
				//ref_p.debug();
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						//printf("Bの追加点:");
						//tmp_cross.debug();
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 0; b < final_B.size(); b++){
					if(isSame(final_A[a],final_B[b])){

						//printf("★A重なり:");
						//final_A[a].debug();
						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 0; a < final_A.size(); a++){
					if(isSame(final_B[b],final_A[a])){

						//printf("★B重なり:");
						//final_B[b].debug();
						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			long double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			//printf("\n\nfrom:%d to:%d\n",from,to);

			long double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				long double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				long double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/M_PI);
				}
				if(fabs(cos_B+1.0) < EPS2){

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/M_PI);
				}


				//printf("i:%d\n",i);

				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					//printf("Aは時計回り\n");
					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					//printf("Bは時計回り\n");
					deg_B = 360.0-deg_B;
				}

				//printf("deg_A:%.3lf deg_B:%.3lf\n",deg_A,deg_B);

				if(deg_A > deg_B){

					//printf("Aの方が大きい\n");

					if(fabs(deg_A-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						//printf("追加点:");
						//final_A[k].debug();
						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{

					//printf("Bの方が大きい\n");

					if(fabs(deg_B-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						//printf("追加点:");
						//final_B[k].debug();
						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(tmp_num < num_max)continue;

			/*printf("\nfrom:%d to:%d\n",from,to);

			printf("交点0:");
			cross_point[0].debug();
			printf("交点1:");
			cross_point[1].debug();

			for(int i = 0; i < 2; i++){

				printf("near[%d]:%d far:%d\n",i,near_from[i],far_from[i]);
			}

			printf("\nポリゴン とどまる\n");
			for(int i = 0; i < A.size(); i++){

				A[i].debug();
			}

			printf("\nポリゴん 動く\n");
			for(int i= 0; i < B.size(); i++){

				B[i].debug();
			}*/

			//printf("tmp_num:%d tmp_dist:%.3lf\n",tmp_num,tmp_dist);


			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	//printf("num_max:%d\n",num_max);

	printf("%.15Lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 0.5
time_ms: 30
memory_kb: 3260
final_rank: 13

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
//#define EPS 0.000000001
using namespace std;



#define EPS 0.000001
#define EPS2   0.00000000001


struct Point{
	Point(long double arg_x,long double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 * (long double a){ return Point(a*x,a*y); }
	Point operator / (long double a){ return Point(x/a,y/a); }

	long double abs(){ return sqrt(norm()); }
	long 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;
	}

	/*void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/
	long double x,y;
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return dist < arg.dist;
	}
	long double dist;
	Point point;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
long double NUM = BIG_NUM;


long double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

int func(long double x1,long double y1,long double x2, long double y2, long double xp, long double yp){
	long double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

long double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//交点を求める関数
Point calc_Cross_Point(long double x1,long double x2,long double x3,long double x4,long double y1,long double y2,long double y3,long double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

long double abs(Vector a){
	return sqrt(norm(a));
}

long double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

long double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

long double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
long double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
long double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
long double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(long double x1,long double y1,long double x2,long double y2,long double xp,long double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	long double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

bool isSame(Point a, Point b){


	return abs(a-b) < EPS;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -1;
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;
}

void  func(){

	Polygon P;

	long double x,y;

	for(int i = 0; i < N; i++){

		scanf("%Lf %Lf",&x,&y);
		P.push_back(Point(x,y));
	}

	int num_max = 0;
	long double ans = 0;

	long double slope,slope2;
	Line base_line; //垂直二等分線

	int num_cross;
	Point cross_point[2],tmp_cross;
	int near_from[2],far_from[2];

	Polygon A,B;
	Polygon final_A,final_B;
	vector<Info> info;

	Vector pre_A,pre_B,now_A,now_B;
	vector<int> match_A,match_B;

	//fromをtoに重ねる
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from)continue;

			slope = calc_slope(Line(P[from],P[to]));

			if(fabs(slope-DBL_MAX) < EPS){ //垂直

				long double tmp_y = (P[from].y+P[to].y)/2.0;

				base_line.p[0] = Point(-NUM,tmp_y); //左
				base_line.p[1] = Point(NUM,tmp_y); //右

			}else if(fabs(slope) < EPS){ //水平

				long double tmp_x = (P[from].x+P[to].x)/2.0;

				base_line.p[0] = Point(tmp_x,-NUM); //下
				base_line.p[1] = Point(tmp_x,NUM); //上

			}else{

				slope2 = -1.0/slope;
				Point tmp_mid = Point((P[from].x+P[to].x)/2.0,(P[from].y+P[to].y)/2.0);

				base_line.p[0] = Point(tmp_mid.x-NUM,tmp_mid.y-NUM*slope2);
				base_line.p[1] = Point(tmp_mid.x+NUM,tmp_mid.y+NUM*slope2);
			}


			//垂直二等分線との交点および隣接点を求める
			num_cross = 0;

			for(int i = 0; i < N; i++){
				Line tmp_line = Line(P[(from+i)%N],P[(from+(i+1))%N]);
				if(!is_Cross(base_line,tmp_line))continue;

				cross_point[num_cross] = calc_Cross_Point(base_line,tmp_line);

				if(num_cross == 0){ //反時計回りで近い方

					near_from[num_cross] = (from+i)%N;
					far_from[num_cross] = (from+(i+1))%N;

				}else{ //反時計回りで遠い方

					near_from[num_cross] = (from+(i+1))%N;
					far_from[num_cross] = (from+i)%N;
				}
				num_cross++;
			}

			bool FLG = true;

			//near[0]→near[1]へ行くまでにfarを通るか
			if(near_from[0] != near_from[1]){

				for(int i = 0; i < N; i++){
					if((near_from[0]+i)%N == near_from[1]){

						break;

					}else if((near_from[0]+i)%N == far_from[0] || (near_from[0]+i)%N == far_from[1]){

						FLG = false;
						break;
					}
				}
			}else{

				//far1→far0が半時計周りか

				for(int i = 0; i < N; i++){
					if((far_from[1]+i)%N == far_from[0]){

						break;
					}else if((far_from[1]+i)%N == near_from[0] || (far_from[1]+i)%N == near_from[1]){

						FLG = false;
						break;
					}
				}
			}

			//near[0]→near[1]を反時計回りで行けるようにする
			if(!FLG){

				swap(cross_point[0],cross_point[1]);
				swap(near_from[0],near_from[1]);
				swap(far_from[0],far_from[1]);
			}



			A.clear();
			B.clear();

			//printf("far1: %d far0:%d\n",far_from[1],far_from[0]);

			//とどまる方のポリゴン
			A.push_back(cross_point[1]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(far_from[1]+i)%N],cross_point[0])||isSame(P[(far_from[1]+i)%N],cross_point[1]))continue;

				A.push_back(P[(far_from[1]+i)%N]);
				//printf("A[%d]",i+1);
				//A[i+1].debug();
				if((far_from[1]+i)%N == far_from[0])break;
			}
			A.push_back(cross_point[0]);
			reverse(A.begin(),A.end()); //cross_point[0]→cross_point[1]の順にする(時計回り)

			//printf("\n");

			//動く方のポリゴン
			B.push_back(cross_point[0]);
			for(int i = 0; i < N; i++){

				if(isSame(P[(near_from[0]+i)%N],cross_point[0])||isSame(P[(near_from[0]+i)%N],cross_point[1]))continue;
				Point ref_p = calc_Reflection_Point(base_line,P[(near_from[0]+i)%N]);
				B.push_back(ref_p);
				//printf("B[%d]",i);
				//ref_p.debug();
				if((near_from[0]+i)%N == near_from[1])break;
			}
			B.push_back(cross_point[1]);


			final_A.clear();
			final_B.clear();

			final_A.push_back(A[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int a = 1; a < A.size(); a++){

				Line work_A = Line(A[a-1],A[a]);

				info.clear();

				for(int b = 0; b < B.size(); b++){

					Line work_B = Line(B[b],B[(b+1)%B.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1]) &&
							!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						tmp_info.dist = calc_dist(A[a-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_A.push_back(A[a]);
					continue;
				}
				sort(info.begin(),info.end());

				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_A.push_back(info[i].point);
				}

				final_A.push_back(A[a]);
			}

			final_B.push_back(B[0]);

			//非端点の交点があるなら、そこで線分を分割する
			for(int b = 1; b < B.size(); b++){

				Line work_B = Line(B[b-1],B[b]);

				info.clear();

				for(int a = 0; a < A.size(); a++){

					Line work_A = Line(A[a],A[(a+1)%A.size()]);
					if(!is_Cross(work_A,work_B))continue;

					Point tmp_cross = calc_Cross_Point(work_A,work_B);
					if(!isSame(tmp_cross,work_B.p[0]) && !isSame(tmp_cross,work_B.p[1]) &&
							!isSame(tmp_cross,work_A.p[0]) && !isSame(tmp_cross,work_A.p[1])){

						Info tmp_info;
						tmp_info.point = tmp_cross;
						//printf("Bの追加点:");
						//tmp_cross.debug();
						tmp_info.dist = calc_dist(B[b-1],tmp_cross);
						info.push_back(tmp_info);
					}
				}
				if(info.size() == 0){

					final_B.push_back(B[b]);
					continue;
				}
				for(int i = 0; i < info.size(); i++){ //A[a-1]から見て近い順

					final_B.push_back(info[i].point);
				}
				final_B.push_back(B[b]);
			}

			match_A.clear();
			match_B.clear();

			//Bと一致する点のインデックスを昇順に列挙する
			for(int a = 1; a < final_A.size()-1; a++){
				for(int b = 0; b < final_B.size(); b++){
					if(isSame(final_A[a],final_B[b])){

						//printf("★A重なり:");
						//final_A[a].debug();
						match_A.push_back(a);
						break;
					}
				}
			}
			for(int b = 1; b < final_B.size()-1; b++){
				for(int a = 0; a < final_A.size(); a++){
					if(isSame(final_B[b],final_A[a])){

						//printf("★B重なり:");
						//final_B[b].debug();
						match_B.push_back(b);
						break;
					}
				}
			}

			//match_A.size() == match_B.size()であるはず

			//cross_point[1]を最後に加える
			match_A.push_back(final_A.size()-1);
			match_B.push_back(final_B.size()-1);

			//角度計算のためのvector
			pre_A = cross_point[1]-cross_point[0];
			pre_B = pre_A;

			long double tmp_dist = calc_dist(cross_point[0],cross_point[1]);

			int index_A = 0,index_B = 0;
			int tmp_num = 1;

			Point pre_P = cross_point[1];

			//printf("\n\nfrom:%d to:%d\n",from,to);

			long double deg_A,deg_B;

			for(int i = 0; i < match_A.size(); i++){

				if(i > 0){
					pre_A = pre_P-final_A[index_A];
					pre_B = pre_P-final_B[index_B];
				}

				now_A = final_A[(index_A+1)]-final_A[index_A];
				now_B = final_B[(index_B+1)]-final_B[index_B];

				long double cos_A = dot(pre_A,now_A)/(abs(now_A)*abs(pre_A));
				long double cos_B = dot(pre_B,now_B)/(abs(now_B)*abs(pre_B));

				if(fabs(cos_A+1.0) < EPS2){

					deg_A = 180.0;
				}else{

					deg_A = acos(cos_A)*(180/M_PI);
				}
				if(fabs(cos_B+1.0) < EPS2){

					deg_B = 180.0;
				}else{

					deg_B = acos(cos_B)*(180/M_PI);
				}


				//printf("i:%d\n",i);

				if(ccw(final_A[index_A],pre_P,final_A[(index_A+1)]) == CLOCKWISE){

					//printf("Aは時計回り\n");
					deg_A = 360.0-deg_A;
				}
				if(ccw(final_B[index_B],pre_P,final_B[(index_B+1)]) == CLOCKWISE){

					//printf("Bは時計回り\n");
					deg_B = 360.0-deg_B;
				}

				//printf("deg_A:%.3lf deg_B:%.3lf\n",deg_A,deg_B);

				if(deg_A > deg_B){

					//printf("Aの方が大きい\n");

					if(fabs(deg_A-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					//より外側に位置する方の辺の長さを足す
					for(int k = index_A+1; k <= match_A[i]; k++){

						//printf("追加点:");
						//final_A[k].debug();
						tmp_dist += calc_dist(final_A[k],final_A[k-1]);
						pre_P = final_A[k-1];
						tmp_num++;
					}

				}else{

					//printf("Bの方が大きい\n");

					if(fabs(deg_B-180.0) < EPS2){ //同一直線上
						//printf("頂点へらし\n");
						tmp_num--;
					}

					for(int k = index_B+1; k <= match_B[i]; k++){

						//printf("追加点:");
						//final_B[k].debug();
						tmp_dist += calc_dist(final_B[k],final_B[k-1]);
						pre_P = final_B[k-1];
						tmp_num++;
					}
				}

				index_A = match_A[i];
				index_B = match_B[i];

			}

			if(tmp_num < num_max)continue;

			/*printf("\nfrom:%d to:%d\n",from,to);

			printf("交点0:");
			cross_point[0].debug();
			printf("交点1:");
			cross_point[1].debug();

			for(int i = 0; i < 2; i++){

				printf("near[%d]:%d far:%d\n",i,near_from[i],far_from[i]);
			}

			printf("\nポリゴン とどまる\n");
			for(int i = 0; i < A.size(); i++){

				A[i].debug();
			}

			printf("\nポリゴん 動く\n");
			for(int i= 0; i < B.size(); i++){

				B[i].debug();
			}*/

			//printf("tmp_num:%d tmp_dist:%.3lf\n",tmp_num,tmp_dist);


			if(tmp_num > num_max){

				num_max = tmp_num;
				ans = tmp_dist;

			}else{ //tmp_num == num_max

				ans = max(ans,tmp_dist);
			}
		}
	}

	//printf("num_max:%d\n",num_max);

	printf("%.15Lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 0.5
time_ms: 30
memory_kb: 3356
final_rank: 19