#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<vector>
#include<cstdio>
#include<complex>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;
#define SZ(v) ((int)(v).size())  
typedef long long LL;
typedef long double LD;
typedef unsigned long long ULL;
typedef pair<int,int> PII;

template<class T>
inline void relax(T& a,const T& b) { a=((a>b) ? a : b); }
template<class T>
inline void tense(T& a,const T& b) { a=((a<b) ? a : b); }

template<class T>
inline void read(T& x)
{
	x=0;
	register bool sign=false;
	register char c;
	for(c=getchar();c<'0' || c>'9';c=getchar()) 
		if(c=='-') sign=true;
	for(;c>='0' && c<='9';c=getchar()) 
		x=(x<<1)+(x<<3)+(c&15);
	if(sign) x=~x+1;
} 

const int N=1e5+5;

int n;
set<int> S[N];
int a[N];

int Mex(set<int>& S)
{
	for(int i=1;;i++) 
		if(!S.count(i)) return i;
	return -1;
}

int main()
{
//	freopen("1.in","r",stdin);
	int i,j;
	
	read(n);	
	for(i=1;i<=n;i++) {
		a[i]=Mex(S[i]);
		S[i].clear();
		for(j=i+i;j<=n;j+=i) 
			S[j].insert(a[i]);
	}
	for(i=1;i<=n;i++) 
		printf("%d ",a[i]);
	puts("");
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define all(v) v.begin(), v.end()
#define rep(i, n) for (ll i = 0; i < (ll)(n); i++)
#define repr(i, n) for (ll i = (n-1); i >= 0; i--)
#define Rep(n) for (ll _ = 0; _ < (ll)(n); _++)
#define popcountll(x) __builtin_popcountll(x)

template <class S>S sum(vector<S>& a) {return accumulate(all(a), S());}
template <class S>S max(vector<S>& a) {return *max_element(all(a));}
template <class S>S min(vector<S>& a) {return *min_element(all(a));}
ll max(int a, ll b) { return max((ll)a, b); } ll max(ll a, int b) { return max(a, (ll)b); }
ll min(int a, ll b) { return min((ll)a, b); } ll min(ll a, int b) { return min(a, (ll)b); }

void Main();
int main() {
  cin.tie(nullptr);
  ios_base::sync_with_stdio(false);
  cout << fixed << setprecision(20);
  Main();
  return 0;
}

#define VM 10
void eprint() { cerr << endl; }
template <class First, class... Rest>
void eprint(First f, Rest... r) {
  cerr << f << ' ';
  eprint(r...);
}
template <class T>
ostream& operator<<(ostream& os, const vector<T>& v) {
  size_t output_num = v.size();
  bool is_omitted = false;
#ifdef VM
  if (VM < output_num) {
    output_num = VM;
    is_omitted = true;
  }
#endif
  os << "[";
  for (size_t i = 0; i < output_num - 1; i++) os << v[i] << ", ";
  os << v[output_num - 1];
  if (is_omitted) os << ", ...";
  return os << "]";
}
template <class S, class T>
ostream& operator<<(ostream& os, const map<S,T>& m) {
  os << "{\n";
  for(auto [k,v]: m){
    os << k << ": " << v << ",\n";
  }
  return os << '}';
}

// n未満の素数のリストを返す
// エラトステレスの篩
vector<int> prime_enum(int n) {
  if(n <= 2) return vector<int>();
  vector<int> res;
  vector<bool> is_prime(n, true);
  is_prime[0] = false;
  is_prime[1] = false;
  for (ll i = 2; i < n; i++) {
    if (!is_prime[i]) continue;
    res.push_back(i);
    for (ll j = 2; i * j < n; j++) {
      is_prime[i * j] = false;
    }
  }
  return res;
}

// 素数リストを用いた実装
// 素数リストはsqrt(n)までの素数を含む必要がある
map<int, int> prime_factor(int n, const vector<int>& primes) {
  map<int, int> res;
  for (int p : primes) {
    if (p * p > n) break;
    while (n % p == 0) {
      res[p]++;
      n /= p;
    }
  }
  if (n != 1) res[n]++;
  return res;
}

int yakusuu(int n, vector<int>& primes){
  auto m = prime_factor(n, primes);
  int ans = 1;
  for(auto [_, c]: m){
    ans += c;
  }
  return ans;
}

using P = pair<int,int>;

void Main(){
  int n; cin >> n;
  auto primes = prime_enum(n);
  for(int i = 1; i <= n; i++){
    cout << yakusuu(i, primes) << ' ';
  }
}
