#include <bits/stdc++.h>

#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define FOR(i,n,m) for(int i=(int)(n); i<=(int)(m); i++)
#define RFOR(i,n,m) for(int i=(int)(n); i>=(int)(m); i--)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define RITR(x,c) for(__typeof(c.rbegin()) x=c.rbegin();x!=c.rend();x++)
#define setp(n) fixed << setprecision(n)

template<class T> bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T> bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; }

#define ll long long
#define vll vector<ll>
#define vi vector<int>
#define pll pair<ll,ll>
#define pi pair<int,int>

#define all(a) (a.begin()),(a.end())
#define rall(a) (a.rbegin()),(a.rend())
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define ins insert

using namespace std;

//-------------------------------------------------
//--Geometry Template (Plane)
//-------------------------------------------------

using lf = double;
const lf EPS = 1e-9;
const lf PI = acos(-1);

#define sgn(x) (((x)<-EPS)?-1:((x)>EPS)?1:0)
#define EQ(x,y) (sgn((y)-(x))==0)

struct V {
    lf x,y;
    V(){}
    V(lf x, lf y):x(x),y(y){}
    V(const V &v):x(v.x),y(v.y){}
    V& operator+=(const V &v){x+=v.x; y+=v.y; return *this;}
    V& operator-=(const V &v){x-=v.x; y-=v.y; return *this;}
    V& operator*=(lf k){x*=k; y*=k; return *this;}
    V& operator/=(lf k){x/=k; y/=k; return *this;}
    V operator+(const V &v){return V(*this)+=v;}
    V operator-(const V &v){return V(*this)-=v;}
    V operator*(lf k){return V(*this)*=k;}
    V operator/(lf k){return V(*this)/=k;}
    V operator-(){return V(-x,-y);}
    lf sq(){return x*x+y*y;}
    lf norm(){return sqrt(sq());}
    V unit(){return V(*this)/=norm();}
    lf arg(){return atan2(y,x);}
    V rot(lf c, lf s){return V(x*c-y*s,x*s+y*c);}
    V rot(lf a){return rot(sin(a),cos(a));}
    V rot90(){return V(-y,x);}
    bool operator<(const V &v){
        if (sgn(x-v.x)) return sgn(x-v.x)<0;
        return sgn(y-v.y)<0;
    }
    friend ostream& operator<<(ostream &os, const V &v){return os<<'('<<v.x<<", "<<v.y<<')';}
};

lf dot(const V &a, const V &b){return a.x*b.x+a.y*b.y;}
lf det(const V &a, const V &b){return a.x*b.y-a.y*b.x;}

int ccw(V a, V b, V c){
    b-=a; c-=a;
    if (sgn(det(b,c))>0) return 1;
    else if(sgn(det(b,c))<0) return -1;
    else if(sgn(dot(b,c))<0) return 2;
    else if(sgn(b.norm()-c.norm())<0) return -2;
    return 0;
}

struct Line {
    V p,q;
    Line(){}
    Line(const V &p, const V &q):p(p),q(q){}
    Line(const Line &l):Line(l.p,l.q){}
    V unit(){return (q-p).unit();}
    lf arg(){return (q-p).arg();}
    Line rot(lf c, lf s){return Line(p.rot(c,s),q.rot(c,s));}
    Line rot(lf a){return Line(p.rot(a),q.rot(a));}
    Line rot90(){return Line(p.rot90(),q.rot90());}
};

struct Segment : Line {
    Segment(){}
    Segment(const V &p, const V &q):Line(p,q){}
    Segment(const Segment &s):Line(s){}
    lf sq(){return (Line::q-Line::p).sq();}
    lf norm(){return (Line::q-Line::p).norm();}
};

// functions about lines
bool parallel(const V &a, const V &b){return EQ(det(a,b),0.0);}
bool parallel(Line &a, Line &b){return EQ(det(a.q-a.p,b.q-b.p),0.0);}
bool orthogonal(const V &a, const V &b){return EQ(dot(a,b),0.0);}
bool orthogonal(Line &a, Line &b){return EQ(dot(a.q-a.p,b.q-b.p),0.0);}

bool samel(Line &a, Line &b){return parallel(a,b)&&EQ(det(a.q-a.p,b.p-a.p),0.0);}
bool insec(Line &a, Line &b){return !parallel(a,b);}
bool insec(Segment &a, Segment &b){
    int c1 = ccw(a.p,a.q,b.p)*ccw(a.p,a.q,b.q);
    int c2 = ccw(b.p,b.q,a.p)*ccw(b.p,b.q,a.q);
    return (c1<=0 && c2<=0);
}
bool insec(Line &a, Segment &b){return ccw(a.p,a.q,b.p)*ccw(a.p,a.q,b.q)<=0;}

// use only if lines have intersection
V cpoint(Line &a, Line &b){
    V r(a.q-a.p);
    r *= det(b.p-a.p,b.q-b.p)/det(a.q-a.p,b.q-b.p);
    return a.p+r;
}

lf distance(V &a, V &b){return (b-a).norm();}
lf distance(Line &l, V &v){return abs(det((l.q-l.p).unit(),v-l.p));}
lf distance(Line &a, Line &b){return (parallel(a,b))?distance(a,b.p):0.0;}
lf distance(Segment &s, V &v){
    if (sgn(dot(s.q-s.p,v-s.p))<0) return distance(s.p,v);
    else if(sgn(dot(s.p-s.q,v-s.q))<0) return distance(s.q,v);
    return distance((Line&)s,v);
}
lf distance(Segment &a, Segment &b){
    if (insec(a,b)) return 0.0;
    lf A=min(distance(a,b.p),distance(a,b.q));
    lf B=min(distance(b,a.p),distance(b,a.q));
    return min(A,B);
}
lf distance(Line &a, Segment &b){
    if (insec(a,b)) return 0.0;
    return min(distance(a,b.p),distance(a,b.q));
}

V subdiv(V &a, V &b, lf m, lf n){return (a*n+b*m)/(m+n);}
V outside(V &a, V &b, lf m, lf n){return (-a*n+b*m)/(m-n);}
V ppfoot(Line &l, V &v){
    V u = (l.q-l.p).unit();
    return l.p+u*dot(u,v-l.p);
}
V reflect(Line &l, V &v){
    V f = ppfoot(l,v);
    return f+(f-v);
}

Line vbsector(V &a, V &b){
    V m = (a+b)/2;
    return Line(m, m+(b-a).rot90());
}
Line absector(V &c, V &a, V &b){
    lf m=(a-c).norm(), n=(b-c).norm();
    return Line(c,subdiv(a,b,m,n));
}
Line perpend(V &c, V &a, V &b){return Line(c,c+(b-a).rot90());}

//-------------------------------------------------
//--Polygon (depends on Geometry Template)
//-------------------------------------------------

//anti-clockwise
struct Polygon {
    vector<V> ps; int n;
    Polygon():n(0){}
    Polygon(int n):n(n),ps(n){}
    void push(const V &v){ps.push_back(v), n++;}
    void pop(){ps.pop_back(), n--;}
    V& operator[](int k){return ps[k%n];}
};

lf area(Polygon &p){
    lf ret=0.0;
    for(int i=0; i<p.n; i++)
        ret+=det(p[i],p[i+1])/2;
    return ret;
}

V gravity(Polygon &p){
    V ret(0,0); lf wsum=0.0;
    for(int i=0; i<p.n; i++){
        lf w = det(p[i],p[i+1]);
        ret+=(p[i]+p[i+1])/3*w;
        wsum+=w;
    }
    return ret/wsum;
}

bool convex(Polygon &p){
    for(int i=0; i<p.n; i++)
        if (sgn(det(p[i]-p[i+1],p[i+1]-p[i+2]))<0) return false;
    return true;
}

Polygon convex_full(vector<V> &ps){
    Polygon ret;
    sort(ps.begin(), ps.end());
    for(int i=0; i<ps.size(); i++){
        while(ret.n>1 && sgn(det(ret[ret.n-1]-ret[ret.n-2],ps[i]-ret[ret.n-1]))<=0) ret.pop();
        ret.push(ps[i]);
    }
    for(int i=ps.size()-2, t=ret.n; i>=0; i--){
        while(ret.n>t && sgn(det(ret[ret.n-1]-ret[ret.n-2],ps[i]-ret[ret.n-1]))<=0) ret.pop();
        ret.push(ps[i]);
    }
    ret.pop();
    return ret;
}

lf diameter(Polygon &p){
    if (p.n==2) return distance(p[0],p[1]);
    lf ret=0;
    int s=0,t=0;
    for(int i=0; i<p.n; i++)
        if (p[t]<p[i]) t = i;
    int ed=t;
    while(s!=ed || t!=p.n){
        chmax(ret, distance(p[s],p[t]));
        (sgn(det(p[s+1]-p[s], p[t]-p[t+1]))>0)? s++ : t++;
    }
    return ret;
}

Polygon convex_cut(Polygon &p, Line &l){
    Polygon ret;
    for(int i=0; i<p.n; i++){
        if (ccw(l.p,l.q,p[i])!=-1) ret.push(p[i]);
        if (ccw(l.p,l.q,p[i])*ccw(l.p,l.q,p[i+1])==-1){
            Segment s(p[i+1],p[i]);
            ret.push(cpoint(l,s));
        }
    }
    return ret;
}

// OUT=0, ON=1, IN=2
int contain(Polygon &p, const V &v){
    int ret=0;
    for(int i=0; i<p.n; i++){
        V a=p[i]-v, b=p[i+1]-v;
        if (a.y>b.y) swap(a,b);
        if (sgn(a.y)<0 && sgn(b.y)>=0 && sgn(det(a,b))<0) ret=2-ret;
        if (EQ(det(a,b),0.0) && sgn(dot(a,b))<=0) return 1;
    }
    return ret;
}

//-------------------------------------------------
//--Circle (depends on Geometry Template)
//-------------------------------------------------

struct Circle {
    V p; lf r;
    Circle(){}
    Circle(const V &v, lf r):p(v),r(r){}
    Circle(const Circle &c):p(c.p),r(c.r){}
    lf area(){return r*r*PI;}
    lf area(lf t){return r*r*t/2;}
};

// functons about circles
bool contain(Circle &c, V &v){return sgn(distance(v,c.p)-c.r)<=0;}
bool contain(Circle &c, Segment &s){
    return sgn(max(distance(s.p,c.p),distance(s.q,c.p))-c.r)<=0;
}
bool insec(Circle &c, Line &l){return sgn(distance(l,c.p)-c.r)<=0;}
bool insec(Circle &c, Segment &s){
    return sgn(distance(s,c.p)-c.r)<=0 && sgn(max(distance(s.p,c.p),distance(s.q,c.p))-c.r)>=0;
}

vector<V> cpoint(Circle &a, Circle &b){
    vector<V> ret;
    V ab(b.p-a.p);
    lf d = ab.norm(), dd = ab.sq();
    lf c = (a.r*a.r+dd-b.r*b.r)/(2.0*a.r*d);
    if (sgn(abs(c)-1.0)>0) return ret;
    if (EQ(abs(c),1.0)){
        c = (c>0)?1:-1;
        ret.push_back(a.p+ab.unit().rot(c,0)*a.r);
    }else{
        lf s = sqrt(1.0-c*c);
        ret.push_back(a.p+ab.unit().rot(c,s)*a.r);
        ret.push_back(a.p+ab.unit().rot(c,-s)*a.r);
    }
    return ret;
}

vector<V> cpoint(Circle &c, Line &l){
    vector<V> ret;
    lf d = distance(l,c.p);
    if (sgn(d-c.r)>0) return ret;
    V h = ppfoot(l,c.p);
    if (EQ(d,c.r)){
        ret.push_back(h);
    }else{
        V r = (l.q-l.p).unit()*sqrt(c.r*c.r-d*d);
        ret.push_back(h+r);
        ret.push_back(h-r);
    }
    return ret;
}

vector<V> tangent(Circle &c, const V &v){
    lf rr=(c.p-v).sq()-c.r*c.r;
    if (sgn(rr)<0) return vector<V>();
    Circle c2(v,sqrt(rr));
    return cpoint(c,c2);
}

vector<V> tangent(Circle &a, Circle &b){
    vector<V> ret, t;
    ret = tangent(a, subdiv(a.p,b.p,a.r,b.r));
    if (!EQ(a.r,b.r)){
        t = tangent(a, outside(a.p,b.p,a.r,b.r));
    }else{
        V r = (b.p-a.p).unit().rot90()*a.r;
        t.push_back(a.p+r);
        t.push_back(a.p-r);
    }
    for(auto p:t) ret.push_back(p);
    return ret;
}

vector<Line> tangent_line(Circle &c, const V &v){
    vector<Line> ret;
    auto t = tangent(c,v);
    for(auto p:t) ret.push_back(Line(v,p));
    return ret;
}

vector<Line> tangent_line(Circle &a, Circle &b){
    vector<Line> ret,t;
    ret = tangent_line(a, subdiv(a.p,b.p,a.r,b.r));
    if (!EQ(a.r,b.r)){
        t = tangent_line(a, outside(a.p,b.p,a.r,b.r));
    }else{
        V r = (b.p-a.p).unit().rot90()*a.r;
        t.push_back(Line(a.p+r, b.p+r));
        t.push_back(Line(a.p-r, b.p-r));
    }
    for(auto l:t) ret.push_back(l);
    return ret;
}

lf carea(Circle &a, Circle &b){
    lf d = distance(a.p,b.p);
    if (sgn(d+a.r-b.r)<=0) return a.area();
    if (sgn(d+b.r-a.r)<=0) return b.area();
    auto cps = cpoint(a,b);
    if (cps.size()<2) return 0.0;
    lf t1 = acos(dot((cps[1]-a.p).unit(),(cps[0]-a.p).unit()));
    if (sgn(det(cps[1]-a.p,cps[0]-a.p))<0) t1=2*PI-t1;
    lf t2 = acos(dot((cps[0]-b.p).unit(),(cps[1]-b.p).unit()));
    if (sgn(det(cps[0]-b.p,cps[1]-b.p))<0) t2=2*PI-t2;
    return a.area(t1)+b.area(t2)-d*(cps[1]-cps[0]).norm()/2;
}

//-------------------------------------------------

int main(void)
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout<<setp(12);
    int n; cin>>n;
    vector<V> ps(n);
    rep(i,n){
        lf x,y; cin>>x>>y;
        ps[i]=V(x,y);
    }
    Polygon poly = convex_full(ps);
    cout<<diameter(poly)<<"\n";
    return 0;
}



Measured memory_bytes: 4164