#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#define INF         1e9
#define EPS         1e-9
#define REP(i,n)    for(ll i=0,i##_len=(n);i<i##_len;++i)
#define REP1(i,n)   for(ll i=1,i##_len=(n);i<=i##_len;++i)
#define REPR(i,n)   for(ll i=(n)-1;i>=0;--i)
#define REPR1(i,n)  for(ll i=(n);i>0;--i)
#define REPC(i,obj) for(auto i:obj)
#define R_UP(a,b)   (((a)+(b)-1)/(b))
#define ALL(obj)    (obj).begin(),(obj).end()
#define SETP        cout << fixed << setprecision(8)
using namespace std;
using ll = long long;
template<typename T = ll>inline T in() { T x; cin >> x; return x; }

struct vec2d {
	double x, y;
	vec2d() {}
	vec2d(double x, double y) :x(x), y(y) {}
	double norm()const {
		return hypot(x, y);
	}
	vec2d operator+(const vec2d&v)const {
		return vec2d(x + v.x, y + v.y);
	}
	vec2d operator-(const vec2d&v)const {
		return vec2d(x - v.x, y - v.y);
	}
	bool operator==(const vec2d&v)const {
		return x == v.x && y == v.y;
	}
	bool operator!=(const vec2d&v)const {
		return !operator==(v);
	}
	static double distance(const vec2d&v0, const vec2d&v1) {
		return (v0 - v1).norm();
	}
	static double cos_arg(const vec2d&v0, const vec2d&v1) {
		return (v0.x * v1.x + v0.y * v1.y) / v0.norm() / v1.norm();
	}
	static double cross_product(const vec2d&v0, const vec2d&v1) {
		return v0.x * v1.y - v0.y * v1.x;
	}
};
vector<vec2d>get_convex_hull(vector<vec2d>input) {
	sort(ALL(input), [](vec2d v0, vec2d v1) {return v0.y < v1.y || (v0.y == v1.y) && v0.x < v1.x; });
	vector<vec2d>output;
	output.push_back(input[0]);
	output.push_back(input[1]);
	for (int i = 2; i < input.size(); ++i) {
		output.push_back(input[i]);
		while (output.end() - 2 != output.begin() && vec2d::cross_product(*(output.end() - 3) - *(output.end() - 2), *(output.end() - 1) - *(output.end() - 2)) > 0) {
			output.erase(output.end() - 2);
		}
	}
	output.push_back(input[input.size() - 2]);
	for (int i = input.size() - 3; i >= 0; --i) {
		output.push_back(input[i]);
		while (output.end() - 2 != output.begin() && vec2d::cross_product(*(output.end() - 3) - *(output.end() - 2), *(output.end() - 1) - *(output.end() - 2)) > 0) {
			output.erase(output.end() - 2);
		}
	}
	output.pop_back();
	return output;
}
double diameter(vector<vec2d>vertex, bool guaranteed = true) {
	if (!guaranteed) {
		vertex = get_convex_hull(vertex);
	}
	auto comp_y = [](const vec2d&v0, const vec2d&v1) {return v0.y < v1.y; };
	int min_y_idx = distance(vertex.begin(), min_element(ALL(vertex), comp_y));
	int max_y_idx = distance(vertex.begin(), max_element(ALL(vertex), comp_y));
	double ret = -1;
	int p = min_y_idx, q = max_y_idx;
	int num = vertex.size();
	do {
		ret = max(vec2d::distance(vertex[p], vertex[q]), ret);
		int next_p = (p + 1) % num;
		int next_q = (q + 1) % num;
		if (vec2d::cross_product(vertex[next_p] - vertex[p], vertex[next_q] - vertex[q]) > 0) {
			q = next_q;
		} else {
			p = next_p;
		}
	} while (p != min_y_idx || q != max_y_idx);
	return ret;
}
signed main() {
	SETP;
	int n = in();
	vector<vec2d>vertex(n);
	REP(i, n) {
		double x = in<double>(), y = in<double>();
		vertex[i] = (vec2d(x, y));
	}
	cout << diameter(vertex) << endl;
}
