Problem: Find the diameter of a convex polygon g. In other words, find a pair of points that have maximum distance between them.

Constraints

* 3 ≤ n ≤ 80000
* -100 ≤ xi, yi ≤ 100
* No point in the g will occur more than once.

Input


n
x1 y1
x2 y2
:
xn yn


The first integer n is the number of points in g.

In the following lines, the coordinate of the i-th point pi is given by two real numbers xi and yi. The coordinates of points are given in the order of counter-clockwise visit of them. Each value is a real number with at most 6 digits after the decimal point.

Output

Print the diameter of g in a line. The output values should be in a decimal fraction with an error less than 0.000001.

Examples

Input

3
0.0 0.0
4.0 0.0
2.0 2.0


Output

4.00


Input

4
0.0 0.0
1.0 0.0
1.0 1.0
0.0 1.0


Output

1.414213562373

Solution (in CPP):

Solution:
#include <stdio.h>
#include <math.h>
#include <vector>
#include <algorithm>
using namespace std;
#define PB push_back
const double eps=1e-9;
const double INF=1e9;
double ABS(double n){return n>=0?n:-n;}
int dcmp(double n){return ABS(n)<eps?0:n>0?1:-1;}
double min(double a,double b){return a>b?b:a;}
double max(double a,double b){return a>b?a:b;}
bool same(double a,double b){return ABS(a-b)<eps;}
struct point{
	double x;
	double y;
	point(){}
	point(double a,double b){x=a;y=b;}
	point operator +(const point &a){return point(x+a.x,y+a.y);}
	point operator -(const point &a){return point(x-a.x,y-a.y);}
	point operator *(const double &a){return point(x*a,y*a);}
	point operator /(const double &a){return point(x/a,y/a);}
	void operator =(const point &a){x=a.x;y=a.y;}
	void operator +=(const point &a){x+=a.x;y+=a.y;}
	void operator -=(const point &a){x-=a.x;y-=a.y;}
	void operator *=(const double &a){x*=a;y*=a;}
	void operator /=(const double &a){x/=a;y/=a;}
	double length(){return sqrt(x*x+y*y);}
	void in(){scanf("%lf%lf",&x,&y);}
	void out(){printf("(%.3lf,%.3lf)",x,y);}
};
bool operator <(const point &a,const point &b){return a.x-b.x<-eps||(ABS(a.x-b.x)<eps&&a.y-b.y<-eps);}
struct segment{
	point a;
	point b;
	segment(){}
	segment(point x,point y){a=x;b=y;}
	void out(){
		printf("segment::");
		a.out();
		b.out();
		printf("\n");
		return ;
	}
};
struct line{
	double A;
	double B;
	double C;
	void pull(){
		if(ABS(A)<eps){
			A/=B;
			C/=B;
			B/=B;
		}
		else{
			B/=A;
			C/=A;
			A/=A;
		}
		return ;
	}
	line(){}
	line(double a,double b,double c){A=a;B=b;C=c;pull();}
	line(point a,point b){
		A=a.y-b.y;
		B=b.x-a.x;
		C=A*a.x+B*a.y;
		pull();
	}
	line(double a,double b,point p){
		A=a;
		B=b;
		C=A*p.x+B*p.y;
		pull();
	}
	line(segment s){
		A=s.a.y-s.b.y;
		B=s.b.x-s.a.x;
		C=A*s.a.x+B*s.a.y;
		pull();
	}
	void out(){
		printf("line:: A=%.3lf B=%.3lf C=%.3lf\n",A,B,C);
		return ;
	}
};
double distance(point a,point b){return (a-b).length();}
double dot(point a,point b){return a.x*b.x+a.y*b.y;}
double cross(point a,point b){return a.x*b.y-b.x*a.y;}
//angle only returns positive value
double angle(point a,point b){return acos(dot(a,b)/(a.length()*b.length()));}
double area(point a,point b,point c){return ABS(cross(b-a,c-a));}
double distance(point a,line b){return (b.A*a.x+b.B*a.y-b.C)/sqrt(b.A*b.A+b.B*b.B);}
point arbitrary_point(line l){
	if(ABS(l.A)<=eps)return point(0,l.C/l.B);
	else return point(l.C/l.A,0);
}
bool between(point a,point b,point c){
	if((a.x-b.x<=eps&&b.x-c.x<=eps)||(eps>=b.x-a.x&&eps>=c.x-b.x))
	if((a.y-b.y<=eps&&b.y-c.y<=eps)||(eps>=b.y-a.y&&eps>=c.y-b.y))
	return true;
	return false;
}
point intersect(line a,line b){
	double x,y,det;
	x=(a.C*b.B-b.C*a.B);
	y=(a.A*b.C-b.A*a.C);
	det=(a.A*b.B-b.A*a.B);
	return point(x,y)/det;
}
bool parallel(line a,line b){return same(a.A*b.B,b.A*a.B);}
double distance(line a,line b){
	if(parallel(a,b))return distance(arbitrary_point(a),b);
	else return 0;
}
double distance(point p,segment s){
	line l(s);
	point a(intersect(line(l.B,-l.A,l.B*p.x-l.A*p.y),l));
	if(between(s.a,a,s.b))return distance(p,a);
	else return min(distance(p,s.a),distance(p,s.b));
}
double distance(segment a,segment b){
	point l(a.a),lm,rm,r(a.b);
	for(int i=0;i<100;i++){
		lm=(l*2+r)/3;
		rm=(l+r*2)/3;
		if(distance(lm,b)>distance(rm,b))l=lm;
		else r=rm;
	}
	return distance(l,b);
}
bool same(line a,line b){return ABS(distance(a,b))<=eps;}
bool vertical(line a,line b){return ABS(a.A*b.A+a.B*b.B)<=eps;}
bool hasintersect(segment a,segment b){
	line l(a),r(b);
	if(parallel(l,r)){
		if(same(l,r))return between(a.a,b.a,a.b)||between(a.a,b.b,a.b)||between(b.a,a.a,b.b)||between(b.a,a.b,b.b);
		else return false;
	}
	else{
		point p(intersect(l,r));
		return between(a.a,p,a.b)&&between(b.a,p,b.b);
	}
}
bool hasintersect(segment a,line b){
	line l(a);
	if(parallel(l,b))return same(l,b);
	else return between(a.a,intersect(l,b),a.b);
}
point intersect(segment a,segment b){return intersect(line(a),line(b));}
point intersect(segment a,line b){return intersect(line(a),b);}
point projection(point a,line b){return intersect(line(b.B,-b.A,a),b);}
point reflection(point a,line b){return projection(a,b)*2-a;}
bool online(point p,line l){return ABS(l.A*p.x+l.B*p.y-l.C)<eps;}
bool onsegment(point p,segment s){return online(p,line(s))&&between(s.a,p,s.b);}
double area(vector<point> &v){
	double ans=0;
	int n=(int)v.size();
	for(int i=1;i<n;i++)ans+=cross(v[i],v[i-1]);
	ans+=cross(v[0],v[n-1]);
	return ABS(ans)/2;
}
bool isconvex(vector<point> &v){
	bool f=true;
	int n=(int)v.size();
	vector<point> nv(v);
	nv.PB(v[0]);
	nv.PB(v[1]);
	for(int i=0;i<n;i++)if(cross(v[i+1]-v[i],v[i+2]-v[i])<-eps){
		f=false;
		break;
	}
	if(f)return true;
	f=true;
	reverse(nv.begin(),nv.end());
	for(int i=0;i<n;i++)if(cross(v[i+1]-v[i],v[i+2]-v[i])<-eps)return false;
	return true;
}
bool onpolygon(point p,vector<point> &v){
	int n=(int)v.size();
	for(int i=1;i<n;i++)if(onsegment(p,segment(v[i],v[i-1])))return true;
	return onsegment(p,segment(v[0],v[n-1]));
}
bool inpolygon(point p,vector<point> &v){
	bool f=false;
	int n=(int)v.size();
	for(int i=0,j=n-1;i<n;j=i++)if((dcmp(v[i].y-p.y)>0!=dcmp(v[j].y-p.y)>0)&&dcmp(p.x-(p.y-v[i].y)*(v[i].x-v[j].x)/(v[i].y-v[j].y)-v[i].x)<0)f=!f;
	return f;
}
vector<point> make_convex(vector<point> v){
	int n=(int)v.size(),sz=0,lst;
	vector<point> ans;
	sort(v.begin(),v.end());
	for(int i=0;i<n;i++){
		while(sz>=2){
			if(cross(v[i]-ans[sz-2],ans[sz-1]-ans[sz-2])>0){
				ans.pop_back();
				sz--;
			}
			else break;
		}
		ans.PB(v[i]);
		sz++;
	}
	lst=sz;
	for(int i=n-2;i>=0;i--){
		while(sz>lst){
			if(cross(v[i]-ans[sz-2],ans[sz-1]-ans[sz-2])>0){
				ans.pop_back();
				sz--;
			}
			else break;
		}
		ans.PB(v[i]);
		sz++;
	}
	ans.pop_back();
	return ans;
}
double diameter(vector<point> &v){
	double ans=0;
	int n=(int)v.size();
	for(int i=0,j=0,nxt=1;i<n;i++){
		while(distance(v[i],v[j])-distance(v[i],v[nxt])<-eps){
			nxt++;
			j++;
			if(nxt>=n)nxt-=n;
			else if(j>=n)j-=n;
		}
		ans=max(ans,distance(v[i],v[j]));
	}
	return ans;
}
int main(){
	int n;
	vector<point> v;
	point temp;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		temp.in();
		v.PB(temp);
	}
	printf("%.20lf\n",diameter(v));
}