#include <bits/stdc++.h>
using namespace std;
long long gcd(long long a, long long b) { return b ? gcd(b, a % b) : a; }
template <class T1, class T2>
struct cmpf {
  bool rev;
  inline bool operator()(const pair<T1, T2>& a, const pair<T1, T2>& b) const {
    return (a.first < b.first) ^ rev;
  }
  cmpf(bool b = false) { rev = b; }
};
template <class T1, class T2>
struct cmps {
  bool rev;
  inline bool operator()(const pair<T1, T2>& a, const pair<T1, T2>& b) const {
    return (a.second < b.second) ^ rev;
  }
  cmps(bool b = false) { rev = b; }
};
string to_string(const char& c) { return string(1, c); }
string to_string(const string& s) { return '"' + s + '"'; }
string to_string(const char* s) { return to_string((string)s); }
string to_string(const bool& b) { return (b ? "true" : "false"); }
string to_string(const vector<bool>& v, const string& sep = " ") {
  string s = "[";
  for (int i = 0; i < v.size(); i++) {
    if (i) {
      s += sep;
    }
    s += to_string(v[i]);
  }
  return s + "]";
}
template <size_t N>
string to_string(const bitset<N>& v) {
  string s = "[";
  for (size_t i = 0; i < N; i++) s += v[i] ? '1' : '0';
  return s + "]";
}
template <class T1, class T2>
string to_string(const pair<T1, T2>& p, const string& sep = ",");
template <class T>
string to_string(const T& v, const string& sep = " ") {
  bool first = true;
  string s = "{";
  for (const auto& x : v) {
    if (!first)
      s += sep;
    else
      first = false;
    s += to_string(x);
  }
  return s + "}";
}
template <class T>
string to_string(const T& v, const int& sz, const string& sep = " ") {
  string s = "[";
  for (int i = 0; i < sz; i++) {
    if (i) {
      s += sep;
    }
    s += to_string(v[i]);
  }
  return s + "]";
}
template <class T1, class T2>
string to_string(const pair<T1, T2>& p, const string& sep) {
  return "(" + to_string(p.first) + sep + to_string(p.second) + ")";
}
long long binpow(const long long& x, const long long& p, const long long& mod) {
  assert(mod > 0);
  if (p == 0) return 1;
  if (p == 1) return x % mod;
  if (p & 1) return (binpow((x * x) % mod, p / 2, mod) * x) % mod;
  return binpow((x * x) % mod, p / 2, mod) % mod;
}
template <class T>
void chmn(T& a, const T& b) {
  if (a > b) a = b;
}
template <class T>
void chmx(T& a, const T& b) {
  if (a < b) a = b;
}
void setIO() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
  cout.tie(nullptr);
}
int chr[8] = {-1, 0, 1, 0, -1, -1, 1, 1};
int chc[8] = {0, 1, 0, -1, -1, 1, -1, 1};
const long long MOD = 1e9 + 7;
const int INIT = 1001001001;
const int MN = 1001;
set<int> row[MN], col[MN];
int G[MN][MN];
void solve() {
  int N;
  cin >> N;
  for (int i = 0; i < N; i++) {
    for (int j = 0; j < N; j++) {
      G[i][j] = -1;
      row[i].insert(j);
      col[i].insert(j);
    }
  }
  for (int i = 0; i < N; i++) {
    for (int j = 0; i + j < N; j++) {
      if (i == j) {
        G[i][j] = 0;
      } else {
        G[i][j] = i + j;
      }
      row[i].erase(G[i][j]);
      col[j].erase(G[i][j]);
    }
  }
  int start;
  for (int i = 1; i < N; i++) {
    for (int j = N - i; j < N; j++) {
      if (i == j) {
        G[i][j] = 0;
      } else if (G[j][i] != -1) {
        G[i][j] = G[j][i];
      } else {
        start = (i + j + (N / 2)) & 1;
        set<int>::iterator rit = row[i].begin();
        set<int>::iterator cit = col[j].begin();
        while (*rit != *cit) {
          if (*rit < *cit) {
            ++rit;
          } else {
            ++cit;
          }
          assert(rit != row[i].end());
          assert(cit != col[j].end());
        }
        G[i][j] = *rit;
      }
      row[i].erase(G[i][j]);
      col[j].erase(G[i][j]);
    }
  }
  for (int i = 0; i < N; i++) {
    for (int j = 0; j < N; j++) {
      if (j) cout << ' ';
      cout << G[i][j];
    }
    cout << endl;
  }
}
int main() {
  setIO();
  long long T = 1;
  while (T-- > 0) solve();
  return 0;
}
