#include <bits/stdc++.h>
using namespace std;
struct line {
  long long left, x, y1, y2;
};
struct cell {
  long long value, lborder, rborder, change;
};
long long minusINF = -2e9, plusINF = 2e9, n, inf = -2e9, nelement = 0;
vector<cell> tree;
bool cmp(line a, line b) {
  if (a.x > b.x) {
    return 0;
  } else if (a.x < b.x) {
    return 1;
  } else {
    if (a.left < b.left) {
      return 1;
    } else {
      return 0;
    }
  }
}
void AddOnSegment(long long i, long long x, long long l, long long r) {
  if (tree[i].lborder == l && tree[i].rborder == r) {
    if (l == r) {
      tree[i].value = tree[i].change + tree[i].value + x;
      tree[i].change = 0;
    } else {
      tree[i].change += x;
    }
  } else if (l > tree[i * 2 + 1].rborder) {
    AddOnSegment(i * 2 + 2, x, l, r);
    tree[i].value = max(tree[i * 2 + 2].value + tree[i * 2 + 2].change,
                        tree[i * 2 + 1].value + tree[i * 2 + 1].change);
  } else if (r <= tree[i * 2 + 1].rborder) {
    AddOnSegment(i * 2 + 1, x, l, r);
    tree[i].value = max(tree[i * 2 + 2].value + tree[i * 2 + 2].change,
                        tree[i * 2 + 1].value + tree[i * 2 + 1].change);
  } else {
    AddOnSegment(i * 2 + 1, x, l, tree[i * 2 + 1].rborder);
    AddOnSegment(i * 2 + 2, x, tree[i * 2 + 2].lborder, r);
    tree[i].value = max(tree[i * 2 + 2].value + tree[i * 2 + 2].change,
                        tree[i * 2 + 1].value + tree[i * 2 + 1].change);
  }
}
long long correct(long long n) {
  long long answer = 1;
  while (answer < n) {
    answer *= 2;
  }
  return answer;
}
void PushToTree(long long i, long long l, long long r, long long x) {
  long long lborder = tree[i].lborder, rborder = tree[i].rborder;
  if (l == lborder && rborder == r) {
    tree[i].value = x;
    return;
  } else if (l >= (lborder + rborder) / 2 + 1) {
    tree[i * 2 + 2].lborder = (lborder + rborder) / 2 + 1;
    tree[i * 2 + 2].rborder = rborder;
    PushToTree(i * 2 + 2, l, r, x);
    tree[i].value = max(tree[i * 2 + 2].value, tree[i * 2 + 1].value);
  } else {
    tree[i * 2 + 1].lborder = lborder;
    tree[i * 2 + 1].rborder = (lborder + rborder) / 2;
    PushToTree(i * 2 + 1, l, r, x);
    tree[i].value = max(tree[i * 2 + 2].value, tree[i * 2 + 1].value);
  }
}
long long GetMaxElement(long long i, long long x) {
  if (tree[i].lborder == tree[i].rborder) {
    if (tree[i].value + tree[i].change == x) {
      return (i - n + 1);
    } else {
      return -1;
    }
  } else {
    tree[i * 2 + 2].change += tree[i].change;
    tree[i * 2 + 1].change += tree[i].change;
    tree[i].change = 0;
    long long ans1 = GetMaxElement(i * 2 + 1, x),
              ans2 = GetMaxElement(i * 2 + 2, x);
    if (ans1 == -1 && ans2 == -1) {
      return -1;
    } else {
      return max(ans1, ans2);
    }
  }
}
long long GetMax(long long l, long long r, long long i) {
  if (l == tree[i].lborder && r == tree[i].rborder) {
    if (l == r) {
      tree[i].value = tree[i].change + tree[i].value;
      tree[i].change = 0;
    }
    return tree[i].value + tree[i].change;
  } else if (l > tree[i * 2 + 1].rborder) {
    tree[i * 2 + 2].change += tree[i].change;
    tree[i * 2 + 1].change += tree[i].change;
    tree[i].change = 0;
    long long ans = GetMax(l, r, i * 2 + 2);
    tree[i].value = max(tree[i * 2 + 1].value + tree[i * 2 + 1].change,
                        tree[i * 2 + 2].value + tree[i * 2 + 2].change);
    return ans;
  } else if (r <= tree[i * 2 + 1].rborder) {
    tree[i * 2 + 2].change += tree[i].change;
    tree[i * 2 + 1].change += tree[i].change;
    tree[i].change = 0;
    long long ans = GetMax(l, r, i * 2 + 1);
    tree[i].value = max(tree[i * 2 + 1].value + tree[i * 2 + 1].change,
                        tree[i * 2 + 2].value + tree[i * 2 + 2].change);
    return ans;
  } else {
    tree[i * 2 + 2].change += tree[i].change;
    tree[i * 2 + 1].change += tree[i].change;
    tree[i].change = 0;
    long long ans = max(GetMax(l, tree[i * 2 + 1].rborder, i * 2 + 1),
                        GetMax(tree[i * 2 + 2].lborder, r, i * 2 + 2));
    tree[i].value = max(tree[i * 2 + 1].value + tree[i * 2 + 1].change,
                        tree[i * 2 + 2].value + tree[i * 2 + 2].change);
    return ans;
  }
  return 0;
}
void GetTree() {
  long long ln = n;
  n = correct(n);
  cell y;
  y.value = inf;
  y.lborder = 0;
  y.rborder = n - 1;
  y.change = nelement;
  tree.resize(n * 2 - 1, y);
  for (long long i = 0; i < ln; i++) {
    long long a;
    a = 0;
    PushToTree(0, i, i, a);
  }
  for (long long i = ln; i < n; i++) {
    PushToTree(0, i, i, inf);
  }
}
int main() {
  long long fig;
  cin >> fig;
  set<long long> all;
  vector<line> figures;
  for (long long i = 0; i < fig; i++) {
    long long a, b, c, d;
    line e, f;
    cin >> a >> b >> c >> d;
    all.insert(b);
    all.insert(d);
    e.left = -1;
    e.x = a;
    e.y1 = b;
    e.y2 = d;
    f.left = 1;
    f.x = c;
    f.y1 = b;
    f.y2 = d;
    figures.push_back(e);
    figures.push_back(f);
  }
  unordered_map<long long, long long> ntc, ctn;
  long long counter = 0;
  for (auto i : all) {
    ntc[i] = counter;
    ctn[counter] = i;
    counter++;
  }
  n = all.size();
  GetTree();
  sort(figures.begin(), figures.end(), cmp);
  for (long long i = 0; i < figures.size(); i++) {
    if (figures[i].left == -1) {
      AddOnSegment(0, 1, ntc[figures[i].y1], ntc[figures[i].y2]);
      if (GetMax(0, n - 1, 0) == fig - 1) {
        long long ans = GetMaxElement(0, fig - 1);
        cout << figures[i].x << ' ' << ctn[ans];
        return 0;
      }
    } else {
      AddOnSegment(0, -1, ntc[figures[i].y1], ntc[figures[i].y2]);
    }
  }
  return 0;
}
