#include <iostream>
#include <algorithm>
#include <utility>
#include <vector>
#include <numeric>
#include <cmath>
#include <iomanip>

template <class T, class U>
inline bool chmin(T &lhs, const U &rhs) {
  if (lhs > rhs) {
    lhs = rhs;
    return true;
  }
  return false;
}

template <class T, class U>
inline bool chmax(T &lhs, const U &rhs) {
  if (lhs < rhs) {
    lhs = rhs;
    return true;
  }
  return false;
}

// [l, r) from l to r
struct range {
  struct itr {
    int i;
    constexpr itr(int i_): i(i_) { }
    constexpr void operator ++ () { ++i; }
    constexpr int operator * () const { return i; }
    constexpr bool operator != (itr x) const { return i != x.i; }
  };
  const itr l, r;
  constexpr range(int l_, int r_): l(l_), r(std::max(l_, r_)) { }
  constexpr itr begin() const { return l; }
  constexpr itr end() const { return r; }
};

// [l, r) from r to l
struct revrange {
  struct itr {
    int i;
    constexpr itr(int i_): i(i_) { }
    constexpr void operator ++ () { --i; }
    constexpr int operator * () const { return i; }
    constexpr bool operator != (itr x) const { return i != x.i; }
  };
  const itr l, r;
  constexpr revrange(int l_, int r_): l(l_ - 1), r(std::max(l_, r_) - 1) { }
  constexpr itr begin() const { return r; }
  constexpr itr end() const { return l; }
};

template <class T>
struct real_constant;

template <>
struct real_constant<double> {
  using value_type = double;
  static constexpr value_type infinity() { return 1e9; }
  static constexpr value_type epsilon() { return 1e-9; }
  static constexpr value_type pi() { return std::acos(-1.0); }
};

template <>
struct real_constant<long double> {
  using value_type = long double;
  static constexpr value_type infinity() { return 1e18; }
  static constexpr value_type epsilon() { return 1e-10; }
  static constexpr value_type pi() { return std::acos(-1.0L); }
};

template <>
struct real_constant<int> {
  using value_type = int;
  static constexpr value_type infinity() { return 1e9; }
  static constexpr value_type epsilon() { return 1; }
};

template <>
struct real_constant<long long> {
  using value_type = long long;
  static constexpr value_type infinity() { return 1e18; }
  static constexpr value_type epsilon() { return 1; }
};

template <class T, class U>
constexpr bool leq(T x, U y) {
  return x - y < real_constant<T>::epsilon();
}
template <class T, class U>
constexpr bool geq(T x, U y) {
  return y - x < real_constant<T>::epsilon();
}
template <class T, class U>
constexpr bool equal(T x, U y) {
  return leq(x, y) && geq(x, y);
}


template <class T>
struct vector_type {
  using value_type = T;
  value_type x, y;
  constexpr vector_type(): x(0), y(0) { }
  constexpr vector_type(value_type x_, value_type y_): x(x_), y(y_) { }
  constexpr vector_type &operator += (const vector_type &rhs) { x += rhs.x; y += rhs.y; return *this; }
  constexpr vector_type operator + (const vector_type &rhs) const { return vector_type(*this) += rhs; }
  constexpr vector_type &operator -= (const vector_type &rhs) { x -= rhs.x; y -= rhs.y; return *this; }
  constexpr vector_type operator - (const vector_type &rhs) const { return vector_type(*this) -= rhs; }
  constexpr vector_type operator - () const { return vector_type(-x, -y); }
  constexpr vector_type &operator *= (value_type rhs) { x *= rhs; y *= rhs; return *this; }
  constexpr vector_type &operator /= (value_type rhs) { x /= rhs; y /= rhs; return *this; }
  constexpr bool operator == (const vector_type &rhs) const { return equal(x, rhs.x) && equal(y, rhs.y); }
  constexpr bool operator != (const vector_type &rhs) const { return !equal(x, rhs.x) || !equal(y, rhs.y); }
};

template <class T, class U>
constexpr vector_type<T> operator * (vector_type<T> v, U rhs) { return v *= rhs; }
template <class T, class U>
constexpr vector_type<T> operator * (U rhs, vector_type<T> v) { return v *= rhs; }
template <class T, class U>
constexpr vector_type<T> operator / (vector_type<T> v, U rhs) { return v /= rhs; }

template <class T>
std::istream& operator >> (std::istream& is, vector_type<T> &v) { return is >> v.x >> v.y; }
template <class T>
std::ostream& operator << (std::ostream& os, const vector_type<T> &v) { return os << v.x << ' ' <<  v.y; }

template <class T>
constexpr T norm(const vector_type<T> &v) { return v.x * v.x + v.y * v.y; }
template <class T>
constexpr T abs(const vector_type<T> &v) { return std::sqrt(norm(v)); }
template <class T>
constexpr T argr(const vector_type<T> &v) { return std::atan2(v.y, v.x); }
template <class T>
constexpr T argd(const vector_type<T> &v) { return argr(v) * 180 / real_constant<T>::pi(); }
template <class T>
constexpr T dist(const vector_type<T> &v, const vector_type<T> &u) { return abs(v - u); }
template <class T>
constexpr T dot(const vector_type<T> &v, const vector_type<T> &u) { return v.x * u.x + v.y * u.y; }
template <class T>
constexpr T cross(const vector_type<T> &v, const vector_type<T> &u) { return v.x * u.y - v.y * u.x; }

template <class T>
constexpr unsigned orthan(const vector_type<T> &v) {
  if (v.x > 0 && v.y >= 0) return 0;
  if (v.x <= 0 && v.y > 0) return 1;
  if (v.x < 0 && v.y <= 0) return 2;
  if (v.x >= 0 && v.y < 0) return 3;
  return 0;
}
template <class T>
constexpr bool cmp_x(const vector_type<T> &v, const vector_type<T> &u) {
  if (equal(v.x, u.x)) return v.y < u.y;
  return v.x < u.x;
}
template <class T>
constexpr bool cmp_y(const vector_type<T> &v, const vector_type<T> &u) {
  if (equal(v.y, u.y)) return v.x < u.x;
  return v.y < u.y;
}
template <class T>
constexpr bool cmp_arg(const vector_type<T> &v, const vector_type<T> &u) {
  if (orthan(v) != orthan(u)) return orthan(v) < orthan(u);
  if (!equal(cross(v, u), 0)) return cross(v, u) > 0;
  return norm(v) < norm(u);
}

template <class T>
using polygon = std::vector<vector_type<T>>;

template <class T>
T closest_pair(typename polygon<T>::iterator begin, typename polygon<T>::iterator end) {
  size_t size = end - begin;
  if (size <= 1) return real_constant<T>::infinity();
  size_t mid = size >> 1;
  auto boundary = (begin + mid) -> x;
  auto res = std::min(closest_pair<T>(begin, begin + mid), closest_pair<T>(begin + mid, end));
  std::inplace_merge(begin, begin + mid, end, cmp_y<T>);
  polygon<T> rectangle;
  for (auto itr1 = begin; itr1 != end; ++itr1) {
    if (geq(std::abs(itr1 -> x - boundary), res)) continue;
    for (auto itr2 = rectangle.rbegin(); itr2 != rectangle.rend(); ++itr2) {
      auto dx = itr1 -> x - itr2 -> x;
      auto dy = itr1 -> y - itr2 -> y;
      if (geq(dy, res)) break;
      res = std::min(res, abs(vector_type<T>(dx, dy)));
    }
    rectangle.push_back(*itr1);
  }
  return res;
}

template <class T>
T closest_pair(polygon<T> poly) {
  std::sort(poly.begin(), poly.end(), cmp_x<T>);
  return closest_pair<T>(poly.begin(), poly.end());
}

int main() {
  int N;
  std::cin >> N;
  polygon<double> poly(N);
  for (auto &p: poly) {
    std::cin >> p;
  }
  std::cout << std::fixed << std::setprecision(20);
  std::cout << closest_pair(poly) << '\n';
  return 0;
}



Measured memory_bytes: 9168