#include <stdio.h>

int main(void) {
    int n, i;
    scanf("%d", &n);

    for (i = 1; i <= n; ++i) {
        printf("%d %d\n",((i << 1) - 1) % n + 1, (i << 1) % n + 1);
    }

    return 0;
}
#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
//optimal subsequences-2 technocup round-3 2020
using namespace std;
using namespace __gnu_pbds;
const int N=2e5+10;
//#define d double
#define F first
#define S second
#define ll long long int
#define FastIO ios_base::sync_with_stdio(false),cin.tie(0)
#define fix std::fixed<<setprecision(6)
const int M=1e9+7;
//const int M=998244353;
#define f(n) for(int i=0;i<n;i++)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define vi vector<int>
#define pb push_back
//#define si set<int>
#define cl(n,m) (ceil(double(n)/double(m)))
#define T() int t; cin>>t; while(t--)
#define pi pair<ll,ll>
//int MOD=998244353;
//const int MOD=1e9+7;
#define endl "\n"
const double PI = 3.141592653589793238460;
#define READ(f) freopen(f, "r", stdin)
#define WRITE(f) freopen(f, "w", stdout)

//ll d1=304933,d2=4395853;

typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

//bitset<N>bs;
//bitset<512>bb[512];
//vector<vector<int>>arr;
//#ifndef ONLINE_JUDGE
//freopen("input.txt", "r" , stdin);
//freopen("output.txt", "w", stdout);
//#endif

ll MOD;

ll power(ll a,ll b)
{
    ll res=1;
    if(a==1)return 1;
    for(;b>0;b>>=1)
    {
        if(b&1)res=(res*a);
        if(res>MOD)res%=MOD;
        a=(a*a);
        if(a>MOD)a=a%MOD;
    }
    return res;
}


bool isPrime[3000000+1];
vector<ll>prime;

vector<int>divisor;

void seive2(int limit)
{
    divisor=vector<int>(limit+1,0);

    for(int i=2;i<=limit;i++)
    {
        if(divisor[i]==0)
        {
            divisor[i]=i;
            if(i*1ll*i<=limit)
            for(int j=i*i;j<=limit;j+=i)divisor[j]=i;
        }
    }
}


void seive(int limit)
{
    isPrime[0]=isPrime[1]=1;

    for(int i=2;i*i<=limit;i++)
    {
        if(!isPrime[i])
        for(int j=i*i;j<=limit;j+=i)
        {
            isPrime[j]=1;
        }
    }
    for(int i=2;i<=limit;i++)if(!isPrime[i])prime.pb(i);
}

#define pii pair<ll,pi>
ll pt[200010],sz[200010],wt[200010];

int finds(int x)
{
    while(pt[x]!=x)
    {
        pt[x]=pt[pt[x]];
        x=pt[x];
    }
    return pt[x];
}

bool unions(int x,int y)
{
    int px=finds(x),py=finds(y);

    if(px==py)return 0;

    if(sz[px]>sz[py])swap(px,py);

    pt[px]=py;
    sz[py]+=sz[px];
    wt[py]+=wt[px];

    return 1;
}


ll bit[200100];

ll query(ll bit[],int x)
{
    ll ans=0;
    for(int i=x;i>0;i-=(i&(-i))){
        ans+=bit[i];
    }
    return ans;
}

void update(ll bit[],int x,ll val)
{
    for(int i=x;i>0;i-=(i&(-i)))
        bit[i]+=val;
}

void update2(ll bit[],int x,ll val)
{
    for(int i=x;i<=600005;i+=(i&(-i)))
        bit[i]+=val;
}


ll query2(ll sum[],int x)
{
    ll ans=0;
    for(int i=x;i<=200005;i+=(i&(-i)))
        ans+=sum[i];
    return ans;
}


void dfs(int s,vector<int>&v,vector<int>&P,int visited[])
{
    visited[s]=1;
    v.pb(s);

    int x=P[s];

    if(!visited[x])
    {
        dfs(x,v,P,visited);
    }
}

set<ll>st;

void recur(int i,ll no)
{
    if(no>=10000)return;

    if(i==prime.size())
    {
        st.insert(no);
        return;
    }

    ll p=no;

    recur(i+1,p);

    for(int j=0;j<=20;j++)
    {
        p*=prime[i];
        if(p>10000)break;
        recur(i+1,p);
    }
}

void solve()
{
    ll n;cin>>n;
    ll sv=n;

    seive(100000);

    st.insert(6);
    st.insert(10);
    st.insert(15);

    vector<ll>v;

    v.pb(6);
    v.pb(10);
    v.pb(15);

    recur(0,6);
    recur(0,10);
    recur(0,15);

    //cout<<st.size()<<endl;

    for(auto it:st)
    {
        if(it!=6 and it!=10 and it!=15)
        {
            v.pb(it);
        }
    }

    for(int i=0;i<n;i++)cout<<v[i]<<' ';

}

int main()
{
    //FastIO;

    int t=1;
//    cin>>t;

	for(int i=1;i<=t;i++)
    {
       // cout<<"Case #"<<i<<": ";
        solve();
        //if(i!=t)cout<<endl;
    }
	return 0;
}
