#include <iostream>
#include <vector>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 200000 + 10;
const double EPS = 1e-7;
const double INF = 1e12;
struct Vec {
    double x,y;
    Vec() {}
    Vec(double x, double y) { 
        this->x = x, this->y = y; 
    }
    void read() { 
        scanf("%lf %lf", &x, &y); 
    }
    void prt() {
        printf("%d %d\n", (int)x,(int)y); 
    }
    double len() { 
        return sqrt(x * x + y * y); 
    }
    double len2() { 
        return x * x + y * y; 
    }
    bool operator <(const Vec& o)const {
        if(y==o.y)
            return x<o.x;
        return y<o.y;
    }
    Vec operator +(const Vec& o)const { 
        return Vec(x + o.x, y + o.y); 
    }
    Vec operator -(const Vec& o)const { 
        return Vec(x - o.x, y - o.y); 
    }
    Vec operator *(const double& k)const { 
        return Vec(k * x, k * y); 
    }
    double operator *(const Vec& o)const {
        return x * o.x + y * o.y; 
    }
    double operator ^(const Vec& o)const {
        return x * o.y - y * o.x; 
    }
    Vec rotate(double ang){ 
        return Vec(x * cos(ang) - y * sin(ang), x * sin(ang) + y * cos(ang)); 
    }
    Vec change(double l) { 
        if(len() < EPS) return *this; 
        return (*this) * (l/len()); 
    }
};


struct Line {
    Vec A1, A2;
    Line() {}
    Line(Vec A1, Vec A2) {
        this->A1 = A1, this->A2 = A2;
    }
    double len() {
        return (A2-A1).len();
    }
    double Len2() {
        return (A2-A1).len2();
    }
};


double disToLine(Vec P, Line L) {
    return abs((P-L.A1)^(L.A2-L.A1)) / L.len();
}
Vec projection(Vec P, Line L) {
    double shadowLen = (P - L.A1) * (L.A2 - L.A1);
    return L.A1 + (L.A2-L.A1).change(shadowLen);
}
Vec rojection(Vec P, Line L) {
    return projection(P,L) * 2 - P;
}
bool onseg(Vec P, Line L) {
    if(disToLine(P, L) > EPS) return 0;
    return (P-L.A1) * (P-L.A2) <= 0;
}

Vec Lineintersect(Line L1, Line L2) {
    // 0 ~ (L2.A1 - L1.A1) ^ (L2.A2 - L1.A1);
    // 1 ~ (L2.A1 - L1.A2) ^ (L2.A2 - L1.A2);
    double F0 = (L2.A1 - L1.A1) ^ (L2.A2 - L1.A1);
    double F1 = (L2.A1 - L1.A2) ^ (L2.A2 - L1.A2);
    if (abs(F1 - F0) < EPS) return Vec(INF, INF);
    return L1.A1 + (L1.A2 - L1.A1) * (- F0 / (F1 - F0));
}

Vec Segintersect(Line L1, Line L2) {
    Vec P = Lineintersect(L1, L2);
    if (P.x == INF) return P;
    if (onseg(P, L1) && onseg(P, L2)) return P;
    return Vec(INF, INF);
}

bool disToSeg(Vec P, Line L) {
    double ans = min((P-L.A1).len(), (P-L.A2).len());
    ans = min(ans, (P - projection(P,L)).len());
    return ans;
}


Vec O;
bool cmp(Vec A, Vec B) {
    return ((A-O)^(B-O)) > 0 || (((A-O)^(B-O)) == 0 && (A-O).len() < (B-O).len());
}
struct Polygon {
    int n; 
    vector<Vec> v;
    Polygon(){
        n=0; v.clear();
    }
    void read() {
        scanf("%d", &n);
        v.resize(2*n);
        for(int i = 0; i < n; i ++){
            Vec tmp; tmp.read();
            v[i] = tmp;
        }
        sort(v.begin(), v.begin()+n);
        v[n]=v[0]; v[n+1]=v[1];
    }

    double getArea() {
        double ans=0;
        for(int i=0;i<n;i++){
            ans=ans+(v[i]^v[i+1]);
        }
        return abs(ans/2);
    }
    bool isConvex() {
        for(int i=0;i<n;i++){
            if( ((v[i+1]-v[i])^(v[i+2]-v[i+1])) < 0 )
                return 0;
        }
        return 1;
    }
    int containVec(Vec P) {
        int flag = 0;
        for(int i=0;i<n;i++) {
            if (onseg(P,Line(v[i], v[i+1]))) return 1;
            Vec Q = Lineintersect(Line(P,Vec(P.x+1,P.y)),Line(v[i],v[i+1]));
            if (Q.x == INF) continue;
            if (onseg(Q, Line(v[i], v[i+1]))) {
                if (abs(Q.y - min(v[i].y, v[i+1].y)) > EPS && Q.x >= P.x)
                    flag ^= 1;
            }
        }
        return flag?2:0;
    }

    Vec stk[N];int top;

    void ConvexHull() {
        O=v[0];
        sort(v.begin() + 1, v.begin() + n, cmp);
        int rig=n-1,lef=rig;
        while(lef && ((v[lef]-O)^(v[rig]-O)) == 0) --lef;
        reverse(v.begin()+lef+1,v.begin()+rig+1);

        stk[0]=v[0], stk[1]=v[1]; top=1;
        for(int i=2;i<n;i++) {
            while(top && ((stk[top]-stk[top-1]) ^ (v[i]-stk[top])) <= EPS) --top;
            stk[++top]=v[i];
        }

        n=top+1;
        for(int i=0;i<=top;i++){
            v[i]=stk[i];
            //stk[i].prt()
        }
        v[n]=v[0], v[n+1]=v[1];
    }
    double Diameter() {
        ConvexHull();
        double ans=0;
        for(int i=0,j=0;i<n;i++){
            while((v[(j+1)%n]-v[i]).len() >= (v[j]-v[i]).len()) j=(j+1)%n;
            ans=max(ans,(v[j]-v[i]).len());
        }
        return ans;
    }
} poly;

int main(){
    poly.read();
    printf("%.8f\n", poly.Diameter());
}



Measured memory_bytes: 5160