#include<bits/stdc++.h>
#define XX first
#define YY second
#define pb emplace_back
#define FOR(i,a,b) for(int (i)=(a);i<(b);++(i))
#define EFOR(i,a,b) for(int (i)=(a);i<=(b);++(i))
#define rep(X,Y) for (int (X) = 0;(X) < (Y);++(X))
#define REP rep
#define rrep(X,Y) for (int (X) = (Y)-1;(X) >=0;--(X))
#define all(X) (X).begin(),(X).end()
#define eb emplace_back

using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef ll LL;
typedef pii PII;
typedef pii PLL;
const ll MOD=1e9+7;

#define rall(X) (X).rbegin(),(X).rend()
#define UNIQUE(X) (X).erase(unique(all(X)),(X).end())
#define reps(X,S,Y) for (int (X) = S;(X) < (Y);++(X))
#define rreps(X,S,Y) for (int (X) = (Y)-1;(X) >= (S);--(X))
template<class T> inline bool MX(T &l,const T &r){return l<r?l=r,1:0;}
template<class T> inline bool MN(T &l,const T &r){return l>r?l=r,1:0;}

const int M = 500;

LL A[M][M];
int dy[] = {-1, 0, 1, 0};
int dx[] = {0, -1, 0, 1};

void Check() {
  set<LL> used;
  rep(i, M) {
    rep(j, M) {
      assert(!used.count(A[i][j]));
      used.insert(A[i][j]);
      rep(k, 4) {
        int ni = i + dy[k];
        int nj = j + dx[k];
        if (ni < 0 || M <= ni) continue;
        if (nj < 0 || M <= nj) continue;
        LL x = A[i][j];
        LL y = A[ni][nj];
        assert(max(x, y)%min(x, y) == 1);
      }
    }
  }
}

using Fact = vector<pii>;
const LL INF = 1e16;
bool queued[M][M];
Fact F[M][M];

LL DeFact(Fact &fs) {
  LL ret = 1;
  for (pii &p : fs) {
    rep(i, p.YY) {
      if (INF/p.XX <= ret) return INF;
      ret *= p.XX;
    }
  }
  return ret;
}

Fact GcdFact(Fact a, Fact b) {
  Fact ret;
  while (a.size() && b.size()) {
    int x = a.back().XX;
    int y = b.back().XX;
    if (x > y) a.pop_back();
    else if (x < y) b.pop_back();
    else {
      assert(x == y);
      ret.eb(pii(x, min(a.back().YY, b.back().YY)));
      a.pop_back();
      b.pop_back();
    }
  }
  reverse(all(ret));
  return ret;
}

set<Fact> qued;
vector<Fact> as = {{pii(2, 6), pii(3, 4), pii(5, 2), pii(7, 1), pii(11, 1), pii(13, 1), pii(17, 1), pii(19, 1), pii(23, 1), pii(29, 1), pii(31, 1)},
  {pii(2, 8), pii(3, 4), pii(5, 2), pii(7, 2), pii(11, 1), pii(13, 1), pii(17, 1), pii(19, 1), pii(23, 1), pii(29, 1)},
  {pii(2, 8), pii(3, 4), pii(5, 2), pii(7, 2), pii(11, 1), pii(13, 1), pii(17, 1), pii(19, 1), pii(23, 1), pii(31, 1)},
  {pii(2, 8), pii(3, 4), pii(5, 2), pii(7, 2), pii(11, 1), pii(13, 1), pii(17, 1), pii(19, 1), pii(23, 1), pii(37, 1)},
  {pii(2, 6), pii(3, 4), pii(5, 2), pii(7, 2), pii(11, 2), pii(13, 2), pii(17, 1), pii(19, 1), pii(23, 1)},
  {pii(2, 3), pii(3, 4), pii(5, 2), pii(7, 3), pii(11, 2), pii(13, 2), pii(17, 1), pii(19, 1), pii(23, 1)},
  {pii(2, 0), pii(3, 6), pii(5, 2), pii(7, 3), pii(11, 2), pii(13, 2), pii(17, 1), pii(19, 1), pii(23, 1)},
};

Fact FindUnused(Fact v) {
  if (!qued.count(v)) return v;

  set<Fact> watched;
  queue<Fact> que;
  que.push(v);
  watched.insert(v);
  while (!que.empty()) {
    Fact fs = que.front(); que.pop();
    int n = fs.size();
    rrep(i, n) {
      if (fs[i].YY == 0) continue;
      fs[i].YY--;
      if (!watched.count(fs)) {
        if (!qued.count(fs)) return fs;
        que.push(fs);
        watched.insert(fs);
      }
      fs[i].YY++;
    }
  }
  return Fact();
}

int cnt = 0;
void FillByLeast(int i, int j) {
  LL l = 1;
  rep(k, 4) {
    int ni = i + dy[k];
    int nj = j + dx[k];
    if (ni < 0 || M <= ni) continue;
    if (nj < 0 || M <= nj) continue;
    assert(A[ni][nj] > 0);
    LL g = __gcd(A[ni][nj], l);
    l /= g;
    assert(INF/l > A[ni][nj]);
    l *= A[ni][nj];
  }
  A[i][j] = l+1;
  cnt += l <= LL(1e15);
}

bool is_composite[114514];
vector<LL> primes;

void Fill() {
  reps(i, 2, 114514) {
    if (is_composite[i]) continue;
    primes.eb(i);
    for (LL j=LL(i)*i; j<114514; j+=i) {
      is_composite[j] = 1;
    }
  }

  vector<int> xs, ys;
  rep(i, M) {
    rep(j, M) {
      if (i%2 != j%2) continue;
      xs.eb(i+j);
      ys.eb(i-j);
    }
  }
  sort(all(xs));
  xs.erase(unique(all(xs)), xs.end());
  sort(all(ys));
  ys.erase(unique(all(ys)), ys.end());

  primes.resize(xs.size() + ys.size());
  deque<LL> X, Y;
  
  int k = 0;
  while (k < primes.size()) {
    if (X.size() < xs.size()) X.eb(primes[k++]);
    if (Y.size() < ys.size()) Y.eb(primes[k++]);
  }
  deque<LL> nX, nY;
  while (X.size()) {
    LL t;
    if (X.size()%2) t = X.back(), X.pop_back();
    else t = X.front(), X.pop_front();
    nX.eb(t);
  }
  while (Y.size()) {
    LL t;
    if (Y.size()%2) t = Y.back(), Y.pop_back();
    else t = Y.front(), Y.pop_front();
    nY.eb(t);
  }
  nX.swap(X);
  nY.swap(Y);
  //random_shuffle(all(X));
  //random_shuffle(all(Y));
  rep(i, M) {
    rep(j, M) {
      if (i%2 != j%2) continue;
      int xidx = lower_bound(all(xs), i+j) - xs.begin();
      assert(xidx < X.size());
      int yidx = lower_bound(all(ys), i-j) - ys.begin();
      assert(yidx < Y.size());
      A[i][j] = X[xidx] * Y[yidx];
    }
  }
  rep(i, M) {
    rep(j, M) {
      if (i%2 == j%2) continue;
      FillByLeast(i, j);
    }
  }
}

signed main(){
  ios_base::sync_with_stdio(false);
  cout<<fixed<<setprecision(0);
  
  Fill();
  //cout << cnt << endl;
  Check();
  int N;
  cin >> N;
  rep(i, N) {
    rep(j, N) {
      if (j) cout << " ";
      cout << A[i][j];
    }
    cout << endl;
  }
}


Measured memory_bytes: 23068