#include<bits/stdc++.h>
using namespace std;

template<size_t max_N, size_t prime_size>
struct Prime{
    bool sieve[max_N];
    int_fast64_t prime[prime_size];
    size_t counter = 0;
    constexpr Prime() : sieve(), prime() {
        for(int_fast64_t i = 0; i < max_N; ++i)
            sieve[i] = true;
        sieve[0] = sieve[1] = false;
        for(int_fast64_t i = 2; i < max_N; ++i){
            if(sieve[i]){
                prime[counter] = i;
                ++counter;
                if(counter >= prime_size)break;
            }
            for(int_fast64_t j = i * i; j < max_N; j += i)
                sieve[j] = false;
        }
    }
    constexpr int_fast64_t operator[](size_t i) const{
        return i < counter ? prime[i] : prime[counter - 1];
    }
};

constexpr Prime<8831, 1000> p = Prime<8831, 1000>();

constexpr int_fast64_t gcd(int_fast64_t a, int_fast64_t b){
    int_fast64_t t(0);
    while(b){
        t = a % b;
        a = b;
        b = t;
    }
    return a;
}

constexpr int_fast64_t lcm(int_fast64_t a, int_fast64_t b){
    return a / gcd(a, b) * b;
}

constexpr int_fast64_t lcm(int_fast64_t a, int_fast64_t b, int_fast64_t c, int_fast64_t d){
    return lcm(lcm(a, b), lcm(c, d));
}

struct Ans{
    int_fast64_t ans[502][502];
    //int_fast64_t mn, mx;
    constexpr size_t v(size_t i){
        return i & 1 ? i / 2 : 999 - i / 2;
        //size_t j(i & 1 ? i / 2 : 999 - i / 2);
        //return j < 250 ? j : j >= 750 ? j : 999 - j;
    }
    constexpr Ans() : ans()/*, mn(numeric_limits<int_fast64_t>::max()), mx(0)*/{
        for(size_t i = 0; i < 501; ++i){
            ans[i][0] = 1;
            ans[501][i] = 1;
            ans[i + 1][501] = 1;
            ans[0][i + 1] = 1;
        }
        for(size_t i = 1; i <= 500; i += 2)
            for(size_t j = 1; j <= 500; j += 2){
                ans[i][j] = p[v(i + j - 2)] * p[v(499 + i - j)];
                //mn = min(mn, ans[i][j]);
                //mx = max(mx, ans[i][j]);
                if(i < 500 && j < 500){
                    ans[i + 1][j + 1] = p[v(i + j)] * p[v(499 + i - j)];
                    //mn = min(mn, ans[i + 1][j + 1]);
                    //mx = max(mx, ans[i + 1][j + 1]);
                }
            }
        for(size_t i = 1; i < 500; i += 2)
            for(size_t j = 1; j < 500; j += 2){
                ans[i + 1][j] = lcm(ans[i][j], ans[i + 2][j], ans[i + 1][j + 1], ans[i + 1][j - 1]) + 1;
                ans[i][j + 1] = lcm(ans[i][j], ans[i][j + 2], ans[i + 1][j + 1], ans[i - 1][j + 1]) + 1;
            }
    }
    constexpr int_fast64_t at(size_t i, size_t j)const{
        return ans[i + 1][j + 1];
    }
};

namespace FastOut {
    static constexpr size_t BUF_SIZE=1<<17, INT_LEN=24, FLT_LEN=400;
    static constexpr char FLT_FMT[]="%.16f";
    static char buf[BUF_SIZE|1]={}, *pos=buf, *endbuf=pos+BUF_SIZE;
    FILE *fout;

    inline void flush() {
        std::fwrite(buf, 1, pos-buf, fout);
        pos = buf;
    }

    inline void print(const char out) {
        if (pos == endbuf) {
            flush();
        }
        *pos++ = out;
    }

    inline void print(const char *out) {
        size_t len=std::strlen(out);
        if (pos + len >= endbuf) {
            flush();
            if (len >= BUF_SIZE) {
                std::fwrite(out, 1, len, fout);
                return;
            }
        }
        std::memcpy(pos, out, len);
        pos += len;
    }

    inline void print(char *out) {
        size_t len=std::strlen(out);
        if (pos + len >= endbuf) {
            flush();
            if (len >= BUF_SIZE) {
                std::fwrite(out, 1, len, fout);
                return;
            }
        }
        std::memcpy(pos, out, len);
        pos += len;
    }


    template <class Char, size_t Len>
    inline void print(const Char (&out)[Len]) {
        print(&out[0]);
    }

    inline void print(const double out) {
        char minibuf[FLT_LEN];
        size_t len=std::snprintf(minibuf, FLT_LEN, FLT_FMT, out);
        if (pos + len >= endbuf) {
            flush();
        }
        std::memcpy(pos, minibuf, len);
        pos += len;
    }

    inline void print(const bool out) {
        print(out? "true":"false");
    }

    template <class Int>
    inline void print(Int out) {
        static_assert(std::is_integral<Int>::value, "For integers only");

        if (out == 0) {
            if (pos == endbuf) {
                flush();
            }
            *pos++ = '0';
            return;
        }

        char minibuf[INT_LEN], *minipos=minibuf+INT_LEN;
        if (std::is_signed<Int>::value && out < 0) {
            if (pos == endbuf) {
                flush();
            }
            *pos++ = '-';
            if (out == std::numeric_limits<Int>::min() && Int(-1) == ~Int(0)) {
                // In two's complement representation, we could not represent the
                // absolute value of minimum (maximum-magnitude negative) value.
                // Without this branch, we would overflow (undefined behavior) by
                // the value.  If we know the input is never the value, we can
                // remove this branch and save (nanoseconds-order) time.
                switch (sizeof out) {
                    case 1:
                        return (void)(print("128"));
                    case 2:
                        return (void)(print("32768"));
                    case 3:
                        return (void)(print("8388608"));
                    case 4:
                        return (void)(print("2147483648"));
                    case 8:
                        return (void)(print("9223372036854775808"));
                    case 16:
                        return (void)(print("170141183460469231731687303715884105728"));
                    default:
                        // Regardless of the number of its bytes, lowest (decimal) digit
                        // is always eight, but other digits depend on it.
                        *--minipos = '8';
                        out /= -10;
                }
            } else {
                out = -out;
            }
        }

        // We know the division is too slow; we wish we could avoid using them
        // TWICE PER LOOP!  ...Now, we notice that compilers are so smart that
        // can replace it by shift operations...  The division-compatible
        //instructions for unsigned are shorter than ones for signed.
        typename std::make_unsigned<Int>::type out_=out;
        do {
            *--minipos = '0' + out_%10;
            out_ /= 10;
        } while (out_ > 0);

        size_t len=(minibuf+INT_LEN)-minipos;
        if (pos + len >= endbuf) {
            flush();
        }
        std::memcpy(pos, minipos, len);
        pos += len;
    }

    class Printer {
        inline void flush() {
            FastOut::flush();
        }

    public:
        Printer(FILE *fout=stdout) {
            FastOut::fout = fout;
        }

        ~Printer() {
            flush();
        }

        template <class T>
        inline void print(const T out) {
            FastOut::print(out);
        }

        template <class First, class... Rest>
        inline void print(const First &out, const Rest &...outs) {
            FastOut::print(out);
            Printer::print(outs...);
        }

        template <class T>
        inline void println(const T out) {
            FastOut::print(out);
            FastOut::print('\n');
        }
    };
}

constexpr Ans a = Ans();
size_t N;

FastOut::Printer out;

int main(){
    scanf("%lu", &N);
    for(size_t i = 0; i < N; ++i){
        for(size_t j = 0; j < N - 1; ++j)out.print(a.at(i, j), ' ');
        out.println(a.at(i, N - 1));
    }
}


Measured memory_bytes: 3200