#include <bits/stdc++.h>

using namespace std;

#ifdef DEBUG
#define LOG(...) cerr << "[" << #__VA_ARGS__ << "]: " << repr(__VA_ARGS__) << endl;
#define MSG(args) cerr << args << "\n";
#define debug(x) x
#else
#define LOG(...)
#define MSG(args)
#define debug(x)
#endif

#define mp make_pair
#define pb push_back
#define sz(x) (int)((x).size())
#define ms(x, v) memset((x), v, sizeof(x))
#define all(x) (x).begin(), (x).end()
#define REP(x, n) for(int x = 0; x < n; x++)
#define REPV(x, v, n) for(int x = v; x < n; x++)
#define REVE(x, n) for(int x = n; x >= 0; x--)

using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
using vii = vector<pii>;
using vvi = vector<vi>;

class UnionFind
{
    int N, cnt;
    vector<int> parent, size;

public:
    UnionFind() { N = 0; } 
    UnionFind(int N) :N(N) { clear(); }

    void clear() { cnt = N; size.assign(N + 1, 1); parent.assign(N + 1, 0); for(int i = 1; i <= N; i++) parent[i] = i; }
    void reset(int sz) { N = sz; clear(); }
    inline int count() const { assert(N != 0); return cnt; }
    int getSetSize(int i) { assert(N != 0 && i >= 1 && i <= N); return size[findSet(i)]; }
    int findSet(int i) { assert(N != 0 && i >= 1 && i <= N); return (parent[i] == i) ? i : (parent[i] = findSet(parent[i])); }
    bool isSameSet(int i, int j) { assert(N != 0 && i >= 1 && i <= N && j >= 1 && j <= N); return findSet(i) == findSet(j); }

    void unite(int i, int j)
    {
        assert(N != 0 && i >= 1 && i <= N && j >= 1 && j <= N);
        int x = findSet(i), y = findSet(j);
        if(x == y)
            return;
        if(size[x] < size[y])
            swap(x, y);
        parent[y] = x;
        size[x] += size[y];
        cnt--;
    }
};

const ld eps = 1e-7;

int N;
pll nails[111];

bool can(ld R)
{
    UnionFind uf(N + 2);
    int up = N + 1, down = N + 2;
    REPV(i, 1, N + 1)
    {
	if(100 - nails[i].second <= 2 * R) uf.unite(i, up);
	if(100 + nails[i].second <= 2 * R) uf.unite(i, down);
    }
    REPV(i, 1, N + 1)
	REPV(j, i + 1, N + 1)
	    if(pow(nails[i].first - nails[j].first, 2) + pow(nails[i].second - nails[j].second, 2) <= 4 * R * R)
		uf.unite(i, j);
    return !uf.isSameSet(up, down);
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> N;
    REPV(i, 1, N + 1) cin >> nails[i].first >> nails[i].second;
    ld lo = 0.0, hi = 500.0;
    while(hi - lo > eps)
    {
	ld mid = (hi + lo) / 2.0;
	if(can(mid)) lo = mid;
	else hi = mid;
    }
    cout.precision(9);
    cout << fixed << lo << "\n";
    return 0;
}

// Standard I/O
#include <iostream>
#include <sstream>
#include <cstdio>
// Standard Library
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cmath>
// Template Class
#include <complex>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
// Container Control
#include <algorithm>

using namespace std;

#define rep( i, n ) for( int i = 0; i < n; ++i )
#define irep( i, n ) for( int i = n-1; i >= 0; --i )
#define reep( i, s, n ) for ( int i = s; i < n; ++i )
#define ireep( i, n, s ) for ( int i = n-1; i >= s; --i )
#define foreach(itr, x) for( typeof(x.begin()) itr = x.begin(); itr != x.end(); ++itr)

#define mp make_pair
#define mt make_tuple
#define pb push_back
#define eb emplace_back
#define all( v ) v.begin(), v.end()
#define fs first
#define sc second
#define vc vector

// for visualizer.html
double SCALE = 1.0;
double OFFSET_X = 0.0;
double OFFSET_Y = 0.0;
#define LINE(x,y,a,b) cerr << "line(" << SCALE*(x) + OFFSET_X << ","	\
	<< SCALE*(y) + OFFSET_Y << ","										\
	<< SCALE*(a) + OFFSET_X << ","										\
	<< SCALE*(b) + OFFSET_Y << ")" << endl;
#define CIRCLE(x,y,r) cerr << "circle(" << SCALE*(x) + OFFSET_X << ","	\
	<< SCALE*(y) + OFFSET_Y << ","										\
	<< SCALE*(r) << ")" << endl;

typedef long long ll;
typedef complex<double> Point;

typedef pair<int, int> pii;
typedef pair<int, pii> ipii;
typedef vector<int> vi;
typedef vector<double> vd;
typedef vector< vector<int> > vii;
typedef vector< vector<double> > vdd;

typedef vector<int>::iterator vi_itr;

const int IINF = 1 << 28;
const int MOD = 1e9+7;
const double INF = 1e30;
const double EPS = 1e-10;
const double PI = acos(-1.0);

// Direction : L U R D
const int dx[] = { -1, 0, 1, 0};
const int dy[] = { 0, -1, 0, 1 };

struct Node {
    vector<int> edge;
    vector<int> weight;
};

struct Graph {
    vector<Node> node;
};

bool is_reachable_graph ( const Graph& g, const int beg_node, const int end_node ) {
    queue<int> que;

    que.push(beg_node);
    vector<bool> exist(g.node.size(), false);
    while ( !que.empty() ) {
        int n = que.front(); que.pop();
        if ( exist[n] ) continue;
        exist[n] = true;

        rep(i, g.node[n].edge.size() ) {
            que.push(g.node[n].edge[i]);
        }
    }

    return exist[end_node];
}

int main()
{
    vector<Point> p;
    int n;
    cin >> n;

    double dist[120][120];
    p.resize(n);
    rep(i, n) {
        double x, y;
        cin >> x >> y;
        p[i] = Point(x, y);
    }

    rep(i, n) rep(j, n) dist[i][j] = sqrt(norm(p[i] - p[j]));
    rep(i, n) dist[n][i] = dist[i][n] = abs(p[i].imag() - 100);
    rep(i, n) dist[n+1][i] = dist[i][n+1] = abs(p[i].imag() + 100);
    dist[n][n+1] = dist[n+1][n] = 200;
    
    vector<tuple<double, int, int>> v;
    rep(i, n) reep(j, i+1, n) v.emplace_back(dist[i][j], i, j);
    rep(i, n) v.emplace_back(abs(p[i].imag() - 100), i, -1);
    rep(i, n) v.emplace_back(abs(p[i].imag() + 100), i, -2);

    sort(all(v));

    rep(i, v.size()) {
        double r = get<0>(v[i]);

        Graph g;
        g.node.resize(n+2);

        rep(i, n+2) reep(j, i+1, n+2) {
            if ( dist[i][j] < r + EPS ) {
                g.node[i].edge.emplace_back(j);
                g.node[j].edge.emplace_back(i);
            }
        }
        
        if ( is_reachable_graph(g, n, n+1) ) {
            printf("%23.16E\n", r / 2.0);
            break;
        }
    }
}
