#!/bin/python

import sys


def get_next_moves(the_board, exclude, the_coord):
    # get all possible moves
    x = the_coord[0]
    y = the_coord[1]
    the_moves = [(x + a, y + b), (x - a, y - b),
                 (x - a, y + b), (x + a, y - b)]
    if a != b:
        the_moves.append((x + b, y + a))
        the_moves.append((x - b, y - a))
        the_moves.append((x - b, y + a))
        the_moves.append((x + b, y - a))

    return_moves = []
    for move in the_moves:
        if move in the_board and move not in exclude:
            return_moves.append(move)
    return return_moves


n = int(raw_input().strip())
possible_knights = []
for i in range(1, n):
    for j in range(1, i + 1):
        possible_knights.append([(i, j)])

# print possible_knights

board = [(i, j) for i in range(n) for j in range(n)]
final_coord = board[-1]
for knight in possible_knights:
    reached_goal = False
    a = knight[0][0]
    b = knight[0][1]
    moves = [(0, 0)]  # so not to make same move twice
    current_locations = [[(0, 0), 0]]  # possible moves to move from

    while len(current_locations) > 0 and not reached_goal:
        next_moves = get_next_moves(board, moves, current_locations[0][0])
        move_number = current_locations[0][1] + 1
        # print next_moves
        for move in next_moves:
            if move == final_coord:
                knight.append(move_number)
                reached_goal = True
                break
            current_locations.append((move, move_number)) # Queue
            moves.append(move)  # add to not make same move twice
        current_locations = current_locations[1:]  # Dequeue
    if not reached_goal:
        knight.append(-1)

to_print_arr = [[0 for _ in range(n - 1)] for _ in range(n - 1)]
for knight in possible_knights:
    to_print_arr[knight[0][0] - 1][knight[0][1] - 1] = knight[1]
    to_print_arr[knight[0][1] - 1][knight[0][0] - 1] = knight[1]

for row in to_print_arr:
    for value in row:
        sys.stdout.write(str(value) + ' ')
    print ''