#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <set>
#include <stack>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

#include <complex>

typedef complex<double> Point;
typedef vector<Point> Polygon;

static const double INF = 1e+10;

#define CURR(P, i) (P[i])
#define NEXT(P, i) (P[(i + 1) % P.size()])

struct Line : public vector<Point> {
  Line() {;}
  Line(Point a, Point b) { push_back(a); push_back(b); }
};

struct Circle {
  Point p;
  double r;
  Circle() {;}
  Circle(Point p, double r) : p(p), r(r) {;}
};

namespace std {
  bool operator<(const Point &lhs, const Point &rhs) {
    return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
  }
}

inline double cross(const Point &a, const Point &b) {
  return imag(conj(a) * b);
}

inline double dot(const Point &a, const Point &b) {
  return real(conj(a) * b);
}

inline int ccw(Point a, Point b, Point c) {
  b -= a;
  c -= a;
  if (cross(b, c) > 0) { return 1; }
  if (cross(b, c) < 0) { return -1; }
  if (dot(b, c) < 0) { return 2; }
  if (norm(b) < norm(c)) { return -2; }
  return 0;
}


bool intersectSS(const Line &s, const Line &t) {
  return ccw(s[0], s[1], t[0]) * ccw(s[0], s[1], t[1]) <= 0 &&
    ccw(t[0], t[1], s[0]) * ccw(t[0], t[1], s[1]) <= 0;
}

bool intersectSP(const Line &s, const Point &p) {
  return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS;
}

Point projection(const Line &l, const Point &p) {
  double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
  return l[0] + t * (l[0] - l[1]);
}

double distanceLP(const Line &l, const Point &p) {
  return abs(p - projection(l, p));
}

double distanceSP(const Line &s, const Point &p) {
  const Point r = projection(s, p);
  if (intersectSP(s, r)) { return abs(r - p); }
  return min(abs(s[0] - p), abs(s[1] - p));
}

double distanceSS(const Line &s, const Line &t) {
  if (intersectSS(s, t)) { return 0; }
  return min(min(distanceSP(s, t[0]), distanceSP(s, t[1])),
             min(distanceSP(t, s[0]), distanceSP(t, s[1])));
}


struct Event {
  int x;
  int out;
  int index;
  Event() {;}
  Event(int x, int out, int index) : x(x), out(out), index(index) {;}
  bool operator<(const Event &rhs) const {
    if (x != rhs.x) { return x < rhs.x; }
    return out < rhs.out;
  }
};

vector<Event> events;
Line lines[100010];
int n;
int main() {
  while (scanf("%d", &n) > 0) {
    events.clear();
    queue<int> que;
    REP(i, n) {
      int x1, y1, x2, y2;
      scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
      if (x2 < x1) { swap(x1, x2); swap(y1, y2); }
      lines[i] = Line(Point(x1, y1), Point(x2, y2));
      events.push_back(Event(x1, 0, i));
      events.push_back(Event(x2, 1, i));
    }
    if (n > 101 * 101 / 2 + 2) {
      puts("0");
      continue;
    }
    sort(events.begin(), events.end());
    double ans = 1e+10;
    set<int> open;
    REP(i, n * 2) {
      Event e = events[i];
      if (e.out) {
        que.push(e.index);
      } else {
        while (!que.empty() && lines[que.front()][1] < e.x - ans) {
          open.erase(que.front());
          que.pop();
        }
        FORIT(it, open) {
          ans = min(ans, distanceSS(lines[e.index], lines[*it]));
        }
        open.insert(e.index);
      }
    }
    printf("%.8f\n", ans);
  }
}

Measured memory_bytes: 0