#include<bits/stdc++.h>
using namespace std;
using ll=long long;
using ld=long double;
ll N;
ll par[105];
ll rank_[105];
void init_uf(ll n_){
for(ll i=0;i<n_;i++){
par[i]=i;
  rank_[i]=0;
}
  }
ll find(ll x){
if(par[x]==x)
  return x;
  return par[x]=find(par[x]);
}
void unite(ll x,ll y){
x=find(x); y=find(y);
  if(x==y)
    return ;
  if(rank_[x]<rank_[y])
    par[x]=y;
  else{
  par[y]=x;if(rank_[x]==rank_[y])rank_[x]++;
  }
}
bool same(ll x,ll y){
x=find(x); y=find(y);
  return x==y;
}
int main(){
  cin>>N;
  vector<ld>X(N);
  vector<ld>Y(N);
  for(ll i=0;i<N;i++){
  cin>>X[i];cin>>Y[i];
  }ld left=0;ld right=100;
  while(0.000001<right-left){
  ld mid=left+(right-left)/2;
    init_uf(N+2);
    for(ll i=0;i<N-1;i++)
      for(ll j=i+1;j<N;j++)
        if(pow(pow(X[i]-X[j],2)+pow(Y[i]-Y[j],2),0.5)<=2*mid)
          unite(i+1,j+1);
    for(ll i=0;i<N;i++){
      if(abs(Y[i]-100)<=2*mid)unite(i+1,0);
      if(abs(Y[i]+100)<=2*mid)unite(i+1,N+1);
    }
      if(same(0,N+1))
        right=mid;
      else
        left=mid;
  }cout<<fixed<<setprecision(7)<<left<<endl;
  return 0;
}
// C++(GCC 9.2.1)
#include <bits/stdc++.h>
using namespace std;
using P = pair<double, pair<int, int>>;
#define repex(i, a, b, c) for(int i = a; i < b; i += c)
#define repx(i, a, b) repex(i, a, b, 1)
#define rep(i, n) repx(i, 0, n)
#define repr(i, a, b) for(int i = a; i >= b; i--)
#define a first
#define b second
double x[111], y[111];

// https://github.com/atcoder/live_library/blob/master/uf.cpp
// UnionFind
// coding: https://youtu.be/TdR816rqc3s?t=726
// comment: https://youtu.be/TdR816rqc3s?t=6822
// -> 一部改変.
struct UnionFind{
    vector<int> d;
    UnionFind(int n = 0): d(n, -1) {}
    int find(int x){
        return (d[x] < 0) ? x : (d[x] = find(d[x]));
    }
    bool unite(int x, int y){
        x = find(x);
        y = find(y);
        if(x == y) return false;
        if(d[x] > d[y]) swap(x, y);
        d[x] += d[y];
        d[y] = x;
        return true;
    }
    bool same(int x, int y){
        return find(x) == find(y);
    }
    int size(int x){
        return -d[find(x)];
    }
};

int main(){
    
    // 1. 入力情報.
    int N;
    scanf("%d", &N);
    rep(i, N) scanf("%lf %lf", &x[i], &y[i]);
    
    // 2. 2点間の距離, 頂点のペア を 保存.
    // -> 頂点 1 … 直線 y = -100, 頂点 N + 2 … 直線 y = 100 とする.
    priority_queue<P, vector<P>, greater<P>> pq;
    rep(i, N){
        P p0, p1;
        // 頂点 1 と 他の頂点との辺 を 追加.
        p0.a = abs(-100.0 - y[i]);
        p0.b.a = 0;
        p0.b.b = i + 1;
        pq.push(p0);
        
        // 頂点 N + 2 と 他の頂点との辺 を 追加.
        p1.a = abs(100.0 - y[i]);
        p1.b.a = N + 1;
        p1.b.b = i + 1;
        pq.push(p1);
    }
    rep(i, N){
        repx(j, i + 1, N){
            double d = hypot(x[i] - x[j], y[i] - y[j]);
            P p;
            p.a = d;
            p.b.a = i + 1;
            p.b.b = j + 1;
            pq.push(p);
        }
    }
    
    // 3. 距離の短い方から順に, 辺を追加.
    double ans = 0.0;
    UnionFind uf(N + 2);
    while(!pq.empty()){
        // 3-1. 辺を取り出す.
        P p = pq.top();
        pq.pop();
        
        // 3-2. 円の直径を更新.
        ans = p.a;
        
        // 3-3. グラフに辺を追加.
        uf.unite(p.b.a, p.b.b);
        
        // 3-4. 辺を追加した結果, 二直線が, 同じ連結成分に含まれてしまう場合は終了.
        if(uf.same(0, N + 1)) break;
        
    }
    
    // 4. 出力.
    printf("%.12lf\n", ans / 2.0);
    return 0;
    
}