There are n detachments on the surface, numbered from 1 to n, the i-th detachment is placed in a point with coordinates (x_i, y_i). All detachments are placed in different points.

Brimstone should visit each detachment at least once. You can choose the detachment where Brimstone starts.

To move from one detachment to another he should first choose one of four directions of movement (up, right, left or down) and then start moving with the constant speed of one unit interval in a second until he comes to a detachment. After he reaches an arbitrary detachment, he can repeat the same process.

Each t seconds an orbital strike covers the whole surface, so at that moment Brimstone should be in a point where some detachment is located. He can stay with any detachment as long as needed.

Brimstone is a good commander, that's why he can create at most one detachment and place it in any empty point with integer coordinates he wants before his trip. Keep in mind that Brimstone will need to visit this detachment, too.

Help Brimstone and find such minimal t that it is possible to check each detachment. If there is no such t report about it.

Input

The first line contains a single integer n (2 ≤ n ≤ 1000) — the number of detachments.

In each of the next n lines there is a pair of integers x_i, y_i (|x_i|, |y_i| ≤ 10^9) — the coordinates of i-th detachment.

It is guaranteed that all points are different.

Output

Output such minimal integer t that it is possible to check all the detachments adding at most one new detachment.

If there is no such t, print -1.

Examples

Input


4
100 0
0 100
-100 0
0 -100


Output


100

Input


7
0 2
1 0
-3 0
0 -2
-1 -1
-1 -3
-2 -3


Output


-1

Input


5
0 0
0 -1
3 0
-2 0
-2 1


Output


2

Input


5
0 0
2 0
0 -1
-2 0
-2 1


Output


2

Note

In the first test it is possible to place a detachment in (0, 0), so that it is possible to check all the detachments for t = 100. It can be proven that it is impossible to check all detachments for t < 100; thus the answer is 100.

In the second test, there is no such t that it is possible to check all detachments, even with adding at most one new detachment, so the answer is -1.

In the third test, it is possible to place a detachment in (1, 0), so that Brimstone can check all the detachments for t = 2. It can be proven that it is the minimal such t.

In the fourth test, there is no need to add any detachments, because the answer will not get better (t = 2). It can be proven that it is the minimal such t.
#include <bits/stdc++.h>
class Scanner {
 private:
  static const int BUFFER_SIZE = 1 << 18;
  char buff[BUFFER_SIZE];
  char *buffPos, *buffLim;
  FILE* file;

 public:
  Scanner(FILE* file) {
    this->file = file;
    buffLim = buff + fread(buff, 1, BUFFER_SIZE, file);
    buffPos = buff;
  }

 private:
  inline void flushBuff() {
    buffLim = buff + fread(buff, 1, BUFFER_SIZE, file);
    if (buffLim == buff) {
      *buffLim++ = '\n';
    }
    buffPos = buff;
  }
  inline bool isWS(char t) { return t <= ' '; }
  inline bool isDig(char t) { return t >= '0' && t <= '9'; }
  inline void nextPos() {
    buffPos++;
    if (buffPos == buffLim) {
      flushBuff();
    }
  }

 public:
  inline char getchar() {
    char ch = *buffPos;
    nextPos();
    return ch;
  }
  inline void next(char* s) {
    while (isWS(*buffPos)) {
      nextPos();
    }
    while (!isWS(*buffPos)) {
      *s = *buffPos;
      s++;
      nextPos();
    }
    *s = '\0';
  }
  inline void nextLine(char* s) {
    while (*buffPos != '\n') {
      nextPos();
    }
    if (*buffPos == '\n') {
      nextPos();
    }
    while (*buffPos != '\n') {
      *s++ = *buffPos;
      nextPos();
    }
    *s = '\0';
  }
  inline int nextInt() {
    while (!isDig(*buffPos) && *buffPos != '-') {
      nextPos();
    }
    int sign = (*buffPos == '-') ? nextPos(), -1 : 1;
    int res = 0;
    while (isDig(*buffPos)) {
      res = res * 10 + *buffPos - '0';
      nextPos();
    }
    return res * sign;
  }
  inline long long nextLong() {
    while (!isDig(*buffPos) && *buffPos != '-') {
      nextPos();
    }
    long long sign = (*buffPos == '-') ? nextPos(), -1 : 1;
    long long res = 0;
    while (isDig(*buffPos)) {
      res = res * 10 + *buffPos - '0';
      nextPos();
    }
    return res * sign;
  }
  inline int n() {
    while (*buffPos < '0' || *buffPos > '9') {
      buffPos++;
      if (buffPos == buffLim) {
        flushBuff();
      }
    }
    int res = 0;
    while (*buffPos >= '0' && *buffPos <= '9') {
      res = res * 10 + (*buffPos - '0');
      buffPos++;
      if (buffPos == buffLim) {
        flushBuff();
      }
    }
    return res;
  }
  inline long long nl() {
    while (*buffPos < '0' || *buffPos > '9') {
      buffPos++;
      if (buffPos == buffLim) {
        flushBuff();
      }
    }
    long long res = 0;
    while (*buffPos >= '0' && *buffPos <= '9') {
      res = res * 10 + (*buffPos - '0');
      buffPos++;
      if (buffPos == buffLim) {
        flushBuff();
      }
    }
    return res;
  }
  inline long long nlm(const int MOD) {
    while (*buffPos < '0' || *buffPos > '9') {
      buffPos++;
      if (buffPos == buffLim) {
        flushBuff();
      }
    }
    long long res = 0;
    while (*buffPos >= '0' && *buffPos <= '9') {
      res = (res * 10 + (*buffPos - '0')) % MOD;
      buffPos++;
      if (buffPos == buffLim) {
        flushBuff();
      }
    }
    return res;
  }
  inline double nextDouble() {
    while (isWS(*buffPos)) {
      nextPos();
    }
    int sign = (*buffPos == '-') ? nextPos(), -1 : 1;
    double res = 0;
    while (isDig(*buffPos)) {
      res = res * 10 + *buffPos - '0';
      nextPos();
    }
    if (*buffPos == '.') {
      nextPos();
      double ep = 1;
      while (isDig(*buffPos)) {
        ep *= 0.1;
        res += ep * (*buffPos - '0');
        nextPos();
      }
    }
    return sign * res;
  }
  inline char nextChar() {
    while (isWS(*buffPos)) nextPos();
    char res = *buffPos;
    nextPos();
    return res;
  }
  ~Scanner() { fclose(file); }
};
Scanner sc(stdin);
std::string cout_list_sep = " ";
template <
    class IterateType, typename = decltype(std::declval<IterateType>().begin()),
    typename = decltype(std::declval<IterateType>().end()),
    typename = typename std::enable_if<std::is_convertible<
        typename std::iterator_traits<
            typename IterateType::iterator>::iterator_category,
        std::input_iterator_tag>::value>::type,
    typename = typename std::enable_if<!std::is_same<
        std::string, typename std::decay<IterateType>::type>::value>::type,
    typename value_type = typename IterateType::value_type>
std::ostream& operator<<(std::ostream& out, const IterateType& a) {
  for (const auto& i : a) out << i << cout_list_sep;
  return out;
}
template <class __TyFirst, class __TySecond>
std::ostream& operator<<(std::ostream& out,
                         const std::pair<__TyFirst, __TySecond>& o) {
  out << "(" << o.first << "," << o.second << ")";
  return out;
}
template <typename _ForwardIterator>
void logArray(_ForwardIterator, _ForwardIterator, const char* = 0) {}
namespace Temps {
template <typename _IntType>
class RangeInt {
  static_assert(std::is_integral<_IntType>::value,
                "RangeInt object must have integral value type");

 public:
  class iterator : public std::iterator<std::input_iterator_tag, _IntType,
                                        _IntType, const _IntType*, _IntType> {
    _IntType val, step;

   public:
    using typename std::iterator<std::input_iterator_tag, _IntType, _IntType,
                                 const _IntType*, _IntType>::reference;
    explicit constexpr iterator(int val, int step) noexcept
        : val(val), step(step) {}
    constexpr iterator& operator++() noexcept {
      val += step;
      return *this;
    }
    constexpr iterator operator++(int) noexcept {
      iterator ret = *this;
      val += step;
      return ret;
    }
    constexpr bool operator==(const iterator& rhs) const noexcept {
      return val == rhs.val;
    }
    constexpr bool operator!=(const iterator& rhs) const noexcept {
      return val != rhs.val;
    }
    constexpr reference operator*() const { return val; }
  };
  const _IntType _begin, _step, _end;
  explicit constexpr RangeInt(const _IntType end) noexcept
      : _begin(0), _step(1), _end(end > 0 ? end : 0) {}
  explicit constexpr RangeInt(const _IntType begin, const _IntType end) noexcept
      : _begin(begin), _step(1), _end(end > begin ? end : begin) {}
  explicit constexpr RangeInt(const _IntType begin, const _IntType end,
                              const _IntType step)
      : _begin(begin),
        _step(step),
        _end(((step > 0 && end <= begin) || (step < 0 && end >= begin))
                 ? begin
                 : (step > 0
                        ? begin + (end - begin + step - 1) / step * step
                        : begin + (begin - end - step - 1) / (-step) * step)) {}
  constexpr iterator begin() const noexcept { return iterator(_begin, _step); }
  constexpr iterator end() const noexcept { return iterator(_end, _step); }
  constexpr _IntType size() const noexcept { return (_end - _begin) / _step; }
};
template <class IntType, typename = typename std::enable_if<
                             std::is_integral<IntType>::value>::type>
inline constexpr RangeInt<IntType> range(IntType arg1) {
  return RangeInt<IntType>(arg1);
}
template <class IntType, typename = typename std::enable_if<
                             std::is_integral<IntType>::value>::type>
inline constexpr RangeInt<IntType> range(IntType arg1, IntType arg2) {
  return RangeInt<IntType>(arg1, arg2);
}
template <class IntType, typename = typename std::enable_if<
                             std::is_integral<IntType>::value>::type>
inline constexpr RangeInt<IntType> range(IntType arg1, IntType arg2,
                                         IntType arg3) {
  return RangeInt<IntType>(arg1, arg2, arg3);
}
}  // namespace Temps
using Temps::range;
namespace Temps {
template <class T>
inline bool checkMin(T& a, T b) {
  return (b < a ? a = b, 1 : 0);
}
template <class T>
inline bool checkMax(T& a, T b) {
  return (a < b ? a = b, 1 : 0);
}
template <class IntType, typename = typename std::enable_if<
                             std::is_integral<IntType>::value>::type>
IntType gcd(const IntType a, const IntType b) {
  return b == 0 ? a : gcd(b, a % b);
}
template <class ForwardIterator, class OutputIterator>
void dissociate(ForwardIterator __begin, ForwardIterator __end,
                OutputIterator __dest) {
  std::vector<typename std::iterator_traits<ForwardIterator>::_IntType> values(
      __begin, __end);
  std::sort(values.begin(), values.end());
  std::unique(values.begin(), values.end());
  while (__begin != __end) {
    *__dest =
        std::distance(values.begin(),
                      std::lower_bound(values.begin(), values.end(), *__begin));
    __dest++;
    __begin++;
  }
}
}  // namespace Temps
using Temps::checkMax;
using Temps::checkMin;
namespace Temps {
template <class Type>
class Vector {
  static_assert(std::is_trivial<Type>::value,
                "Temps::Vector can only be used for trival types");

 public:
  typedef Type& reference;
  typedef const Type& const_reference;
  class iterator : public std::iterator<std::random_access_iterator_tag, Type> {
   public:
    friend class Vector;
    using typename std::iterator<std::random_access_iterator_tag,
                                 Type>::difference_type;
    using
        typename std::iterator<std::random_access_iterator_tag, Type>::pointer;
    using typename std::iterator<std::random_access_iterator_tag,
                                 Type>::reference;

   private:
    pointer ptr;
    iterator(pointer ptr) : ptr(ptr) {}

   public:
    bool operator==(const iterator rhs) const { return ptr == rhs.ptr; }
    bool operator!=(const iterator rhs) const { return ptr != rhs.ptr; }
    bool operator<(const iterator rhs) const { return ptr < rhs.ptr; }
    bool operator<=(const iterator rhs) const { return ptr <= rhs.ptr; }
    bool operator>(const iterator rhs) const { return ptr > rhs.ptr; }
    bool operator>=(const iterator rhs) const { return ptr >= rhs.ptr; }
    iterator operator++() { return iterator(++ptr); }
    iterator operator++(int) { return iterator(ptr++); }
    iterator operator--() { return iterator(--ptr); }
    iterator operator--(int) { return iterator(ptr--); }
    iterator operator+(const difference_type dif) const {
      return iterator(ptr + dif);
    }
    iterator operator-(const difference_type dif) const {
      return iterator(ptr - dif);
    }
    iterator operator+=(const difference_type dif) {
      ptr += dif;
      return *this;
    }
    iterator operator-=(const difference_type dif) {
      ptr -= dif;
      return *this;
    }
    difference_type operator-(const iterator& rhs) const {
      return ptr - rhs.ptr;
    }
    operator pointer() { return ptr; }
  };

 protected:
  Type* a = nullptr;
  unsigned int _capacity = 0, _size = 0;
  void __grow_capacity(unsigned int least_size) {
    if (_capacity >= least_size) {
      return;
    }
    if (_capacity == 0) {
      _capacity = 1;
    }
    while (_capacity < least_size) {
      _capacity = _capacity * 2;
    }
    a = static_cast<Type*>(realloc(a, sizeof(Type) * _capacity));
  }

 public:
  Vector() = default;
  explicit Vector(unsigned int size, const Type& initial_value = Type())
      : _capacity(size), _size(size) {
    a = static_cast<Type*>(malloc(sizeof(Type) * _capacity));
    Type *__first = a, *const __last = a + _size;
    while (__first != __last) {
      *__first++ = initial_value;
    }
  }
  Vector(const Vector& rhs) : _capacity(rhs._size), _size(rhs._size) {
    a = static_cast<Type*>(malloc(sizeof(Type) * _capacity));
    Type *__first = a, *__r_p = rhs.a, *const __last = a + _size;
    while (__first != __last) {
      *__first++ = *__r_p++;
    }
  }
  Vector(Vector&& rhs) : _capacity(rhs._capacity), _size(rhs._size) {
    a = rhs.a;
    rhs.a = nullptr;
  }
  template <typename Container,
            typename = decltype(std::declval<Container>().begin(),
                                std::declval<Container>().end())>
  Vector(const Container& list)
      : _capacity(std::distance(list.begin(), list.end())), _size(_capacity) {
    a = static_cast<Type*>(malloc(sizeof(Type) * _capacity));
    Type* p = a;
    for (const auto& i : list) {
      *p++ = i;
    }
  }
  template <
      typename _InputIterator,
      typename = typename std::enable_if<std::is_convertible<
          typename std::iterator_traits<_InputIterator>::iterator_category,
          std::input_iterator_tag>::value>::type>
  explicit Vector(_InputIterator __first, _InputIterator __last) {
    _size = _capacity = std::distance(__first, __last);
    a = static_cast<Type*>(malloc(sizeof(Type) * _capacity));
    Type* p = a;
    while (__first != __last) {
      *p++ = *__first++;
    }
  }
  inline bool empty() const { return _size == 0; }
  inline unsigned int size() const { return _size; }
  inline unsigned int capacity() const { return _capacity; }
  void reserve(unsigned int __capacity) {
    _capacity = __capacity;
    if (_size > _capacity) {
      _size = _capacity;
    }
    a = static_cast<Type*>(realloc(a, sizeof(Type) * _capacity));
  }
  void resize(unsigned int __size) {
    if (_size > __size) {
      _size = __size;
      return;
    }
    __grow_capacity(__size);
    Type *__un = a + _size, *const __ed = a + __size;
    while (__un != __ed) {
      *__un++ = Type();
    }
    _size = __size;
  }
  inline void clear() { resize(0); }
  Vector& operator=(const Vector& rhs) {
    __grow_capacity(rhs._size);
    _size = rhs._size;
    Type* __first = a;
    const Type *const __last = a + _size, *__r_p = rhs.a;
    while (__first != __last) {
      *__first++ = *__r_p++;
    }
    return *this;
  }
  Vector& operator=(Vector&& rhs) {
    _size = rhs._size;
    _capacity = rhs._capacity;
    free(a);
    a = rhs.a;
    rhs.a = nullptr;
    return *this;
  }
  Type operator[](const unsigned int id) const { return a[id]; }
  Type& operator[](const unsigned int id) { return a[id]; }
  Type front() const { return a[0]; }
  Type& front() { return a[0]; }
  Type back() const { return a[_size - 1]; }
  Type& back() { return a[_size - 1]; }
  void pop_back() { _size--; }
  Vector& push_back(const Type& b) {
    __grow_capacity(_size + 1);
    a[_size] = b;
    _size++;
    return *this;
  }
  Vector& push_back(const Vector& rhs) {
    __grow_capacity(_size + rhs._size);
    for (const auto& i : rhs) {
      a[_size++] = i;
    }
    return *this;
  }
  Vector& push_back(const std::initializer_list<Type>& rhs) {
    __grow_capacity(_size + rhs.size());
    for (const auto& i : rhs) {
      a[_size++] = i;
    }
    return *this;
  }
  inline iterator begin() const { return iterator(a); }
  inline iterator end() const { return iterator(a + _size); }
  ~Vector() { free(a); }
};
}  // namespace Temps
using Temps::Vector;
void preInit();
void init();
void solve();
int32_t main() {
  preInit();
  init();
  solve();
  return 0;
}
constexpr int N = 1005;
std::vector<std::pair<int, int> > row[N], col[N];
struct position {
  int x, y;
} a[N];
int fa[N], bel[N], cx[N], cy[N];
int n, block_cnt;
inline int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
inline void merge(int x, int y) {
  int fx = find(x), fy = find(y);
  if (fx != fy) {
    --block_cnt;
    fa[fy] = fx;
  }
}
inline bool CheckPoint(int x1, int y1, int x2, int y2, int lim) {
  if (x1 == x2 && std::abs(y1 - y2) <= 2ll * lim) return true;
  if (y1 == y2 && std::abs(x1 - x2) <= 2ll * lim) return true;
  if (std::abs(x1 - x2) <= lim && std::abs(y1 - y2) <= lim) return true;
  return false;
}
inline bool check(long long lim) {
  block_cnt = n;
  for (int i = 1; i <= n; ++i) fa[i] = i;
  for (int i = 1; i <= n; ++i) {
    for (int j = i + 1; j <= n; ++j) {
      if (a[i].x == a[j].x && std::abs(a[i].y - a[j].y) <= lim) merge(i, j);
      if (a[i].y == a[j].y && std::abs(a[i].x - a[j].x) <= lim) merge(i, j);
    }
  }
  for (int i = 1; i <= n; ++i) bel[i] = find(i);
  if (block_cnt > 4)
    return false;
  else if (block_cnt == 1)
    return true;
  else if (block_cnt == 2) {
    for (int i = 1; i <= n; ++i) {
      for (int j = i + 1; j <= n; ++j) {
        if (bel[i] == bel[j]) continue;
        if (CheckPoint(a[i].x, a[i].y, a[j].x, a[j].y, lim)) return true;
      }
    }
  } else if (block_cnt == 3) {
    for (int i = 1; i <= cx[0]; ++i) {
      long long curx = cx[i];
      for (int j = 1; j < (int)row[i].size(); ++j) {
        int index_L = row[i][j - 1].second, index_R = row[i][j].second;
        long long yL = row[i][j - 1].first, yR = row[i][j].first;
        if (bel[index_L] != bel[index_R] && yR - yL <= 2ll * lim) {
          for (int k = 1; k <= n; ++k) {
            if (bel[index_L] == bel[k] || bel[index_R] == bel[k]) continue;
            if (!(yR - lim <= a[k].y && a[k].y <= yL + lim)) continue;
            if (std::abs(a[k].x - curx) <= lim) return 1;
          }
        }
      }
    }
    for (int i = 1; i <= cy[0]; ++i) {
      long long cury = cy[i];
      for (int j = 1; j < (int)col[i].size(); ++j) {
        int index_L = col[i][j - 1].second, index_R = col[i][j].second;
        long long xL = col[i][j - 1].first, xR = col[i][j].first;
        if (bel[index_L] != bel[index_R] && xR - xL <= 2ll * lim) {
          for (int k = 1; k <= n; ++k) {
            if (bel[index_L] == bel[k] || bel[index_R] == bel[k]) continue;
            if (!(xR - lim <= a[k].x && a[k].x <= xL + lim)) continue;
            if (std::abs(a[k].y - cury) <= lim) return true;
          }
        }
      }
    }
  } else {
    for (int i = 1; i <= cx[0]; ++i) {
      long long curx = cx[i];
      for (int j = 1; j < (int)row[i].size(); ++j) {
        int index_L_1 = row[i][j - 1].second, index_R_1 = row[i][j].second;
        long long yL = row[i][j - 1].first, yR = row[i][j].first;
        if (bel[index_L_1] == bel[index_R_1]) continue;
        for (int k = 1; k <= cy[0]; ++k) {
          long long cury = cy[k];
          for (int l = 1; l < (int)col[k].size(); ++l) {
            int index_L_2 = col[k][l - 1].second, index_R_2 = col[k][l].second;
            long long xL = col[k][l - 1].first, xR = col[k][l].first;
            if (bel[index_L_2] == bel[index_R_2]) continue;
            if (bel[index_L_2] == bel[index_L_1] ||
                bel[index_L_2] == bel[index_R_1])
              continue;
            if (bel[index_R_2] == bel[index_L_1] ||
                bel[index_R_2] == bel[index_R_1])
              continue;
            if (!(xR - lim <= curx && curx <= xL + lim)) continue;
            if (!(yR - lim <= cury && cury <= yR + lim)) continue;
            if (std::abs(curx - xL) > lim || std::abs(curx - xR) > lim)
              continue;
            if (std::abs(cury - yL) > lim || std::abs(cury - yR) > lim)
              continue;
            return true;
          }
        }
      }
    }
  }
  return false;
}
void preInit() {}
void init() {
  n = sc.n();
  for (int i = 1; i <= n; ++i) {
    a[i].x = sc.nextInt();
    a[i].y = sc.nextInt();
    cx[++cx[0]] = a[i].x;
    cy[++cy[0]] = a[i].y;
  }
  std::sort(cx + 1, cx + 1 + cx[0]);
  std::sort(cy + 1, cy + 1 + cy[0]);
  cx[0] = std::unique(cx + 1, cx + 1 + cx[0]) - cx - 1;
  cy[0] = std::unique(cy + 1, cy + 1 + cy[0]) - cy - 1;
}
void solve() {
  for (int i = 1; i <= n; ++i) {
    int curx = std::lower_bound(cx + 1, cx + 1 + cx[0], a[i].x) - cx,
        cury = std::lower_bound(cy + 1, cy + 1 + cy[0], a[i].y) - cy;
    row[curx].push_back(std::make_pair(a[i].y, i));
    col[cury].push_back(std::make_pair(a[i].x, i));
  }
  for (int i = 1; i <= cx[0]; ++i) std::sort(row[i].begin(), row[i].end());
  for (int i = 1; i <= cy[0]; ++i) std::sort(col[i].begin(), col[i].end());
  int l = 0, r = std::numeric_limits<int>::max();
  while (l < r) {
    int mid = ((long long)l + r) >> 1;
    if (check(mid))
      r = mid;
    else
      l = mid + 1;
  }
  printf("%d\n", l == std::numeric_limits<int>::max() ? -1 : l);
}
