#include <algorithm>
#include <array>
#include <assert.h>
#include <bitset>
#include <chrono>
#include <cmath>
#include <complex>
#include <cstring>
#include <functional>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <istream>

#include <map>
#include <math.h>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace asl
{
    
    template <typename numeric_type>
    class point
    {
    public:
        numeric_type x, y;

        point(numeric_type x = 0, numeric_type y = 0) : x(x), y(y) {}

        point<numeric_type> &operator-=(const point<numeric_type> &ri)
        {
            x -= ri.x;
            y -= ri.y;
            return *this;
        }

        friend point<numeric_type> operator-(const point<numeric_type> &a, const point<numeric_type> &b)
        {
            return point<numeric_type>(a) -= b;
        }

    };

    template <typename numeric_type>
    std::istream &operator>>(std::istream &is, point<numeric_type> &p)
    {
        return is >> p.x >> p.y;
    }

    template <typename numeric_type>
    numeric_type norm(point<numeric_type> a)
    {
        return a.x * a.x + a.y * a.y;
    }

    template <typename numeric_type, typename float_type = double>
    float_type abs(point<numeric_type> a)
    {
        return sqrtl(norm(a));
    }

    template <typename numeric_type>
    numeric_type cross(point<numeric_type> a, point<numeric_type> b)
    {
        return a.x * b.y - a.y * b.x;
    }

    template <typename numeric_type>
    numeric_type area2(point<numeric_type> a, point<numeric_type> b, point<numeric_type> c)
    {
        return cross(b - a, c - a);
    }

#include <stdint.h>

    template <typename T>
    std::istream &operator>>(std::istream &is, std::vector<T> &vec)
    {
        for (auto &value : vec)
            is >> value;
        return is;
    }

} 

#include <experimental/optional>

#define _NEXT(i) (((i) + 1) == n ? 0 : ((i) + 1))

namespace asl
{
    template <typename numeric_type>
    using polygon = std::vector<point<numeric_type>>;

    template <typename numeric_type>
    std::vector<std::pair<int, int>> antipodal(const polygon<numeric_type> &P)
    {
        std::vector<std::pair<int, int>> ans;
        int n = P.size();

        if (P.size() == 2)
            ans.push_back({0, 1});

        if (P.size() < 3)
            return ans;

        int q0 = 0;

        while (std::abs(area2(P[n - 1], P[0], P[_NEXT(q0)])) > std::abs(area2(P[n - 1], P[0], P[q0])))
            ++q0;

        for (int q = q0, p = 0; q != 0 && p <= q0; ++p)
        {
            ans.push_back({p, q});

            while (std::abs(area2(P[p], P[_NEXT(p)], P[_NEXT(q)])) > std::abs(area2(P[p], P[_NEXT(p)], P[q])))
            {
                q = _NEXT(q);
                if (p != q0 || q != 0)
                    ans.push_back({p, q});
                else
                    return ans;
            }

            if (std::abs(area2(P[p], P[_NEXT(p)], P[_NEXT(q)])) == std::abs(area2(P[p], P[_NEXT(p)], P[q])))
            {
                if (p != q0 || q != n - 1)
                    ans.push_back({p, _NEXT(q)});
                else
                    ans.push_back({_NEXT(p), q});
            }
        }

        return ans;
    }

    template <typename numeric_type, typename float_type = double>
    float_type diameter(const polygon<numeric_type> &pol)
    {
        float_type res = 0;
        for (auto puv : antipodal(pol))
        {
            int u = puv.first, v = puv.second;
            res = std::max(res, abs(pol[u] - pol[v]));
        }
        return res;
    }

} 

#include <random>

#define endl '\n'

using namespace asl;
using namespace std;

int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.precision(12);
    cout << fixed;

    int n;
    cin >> n;

    polygon<double> pol(n);
    cin >> pol;

    cout << diameter(pol) << endl;

    return 0;
}





Measured memory_bytes: 5276