#include"bits/stdc++.h"
#define int long long
#define _overload3(_1,_2,_3,name,...) name
#define _rep(i,n) repi(i,0,n)
#define repi(i,a,b) for(int i=(a);i<(b);++i)
#define rep(...) _overload3(__VA_ARGS__,repi,_rep,)(__VA_ARGS__)
#define itr(i,x) for(auto i=(x).begin();i!=(x).end();++i)
#define All(x) (x).begin(),(x).end()
#define rAll(x) (x).rbegin(),(x).rend()
#define gridif(a,x,b) if((a)<=(x)&&(x)<(b))

using namespace std;
typedef pair<int,int> P;
typedef int ll;
constexpr int mod=1000000007;

void YN(bool flg){cout<<(flg?"YES":"NO")<<endl;}
void Yn(bool flg){cout<<(flg?"Yes":"No")<<endl;}
void yn(bool flg){cout<<(flg?"yes":"no")<<endl;}

int roundup(int a,int b){return (a-1)/b+1;}
P bisearch(int l,int r,function<bool(int)> f){
	while(l+1<r){
		int m=(l+r)/2;
		bool flag=f(m);
		if(flag) r=m;
		else l=m;
	}
	return P(l,r);
}
int Sqrt(int n){
	return bisearch(0,n,[n](int x){return x>n/x;}).first;
}
bool square(int n){
	int s=Sqrt(n);
	return s*s==n;
}
int digitsum(int n,int b){
	if(b<2) return -1;
	if(n<b) return n;
	return digitsum(n/b,b)+n%b;
}
int npow(int a,int x){
	int ans=1;
	while(x>0){
		if(x%2==1) ans*=a;
		a*=a;
		x>>=1;
	}
	return ans;
}
int mpow(int a,int x){
	int ans=1;
	while(x>0){
		if(x%2==1) (ans*=a)%=mod;
		(a*=a)%=mod;
		x>>=1;
	}
	return ans;
}
int m_inv(int n){return mpow(n,mod-2);}
int divisor(int x){//約数の個数
	int i=2,ans=1,num=1;
	int N=x;
	while(i<=Sqrt(N)){
		if(x%i){ 
			i++;
			ans*=num;
			num=1;
			if(x==1) break;
		}
		else{
			x/=i;
			num++;
		}
	}
	if(x!=1) ans*=2;
	return ans;
}
vector<int> split(string s,int a){
	if(a<0||a>s.length()) return {-1,-1};
	string l="0",r="0";
	if(a!=0) l=s.substr(0,a);
	if(a!=s.length()) r=s.substr(a);
	return{stoll(l),stoll(r)};
}
string xal_number(int n,int x){
	if(x>36) return "out of use";
	if(n==0) return "";
	string s;
	int i=n%x;
	char a = i + ( i >= 10 ? 'A'-10 : '0' );
	s=xal_number(n/x,x)+a;
	return s;
}
int gcd(int x,int y){return y?gcd(y,x%y):x;}
int lcm(int x,int y){return x*y/gcd(x,y);}

class mint {
 private:
  ll _num,_mod;
  mint set(ll num){ 
      _num = num ;
      if(_num>=0) _num%=_mod;
      else _num+=(1-(_num+1)/_mod)*_mod; 
      return *this;
  }
  ll imod(ll n){return mpow(n , _mod-2);}
 public:
  mint(){ _num = 0;_mod=mod; }
  mint(ll num){ _mod = mod; _num = num % mod; }
  mint(ll num,ll M){ _mod=M;set(num); }
  mint(const mint &cp){_num=cp._num;_mod=cp._mod;}
  mint operator= (ll x){ return set(x); }
  mint operator+ (ll x){ return mint(_num + (x % _mod) , _mod); }
  mint operator- (ll x){ return mint(_num - (x % _mod), _mod); }
  mint operator* (ll x){ return mint(_num * (x % _mod) , _mod); }
  mint operator/ (ll x){ return mint(_num * imod(x) , _mod);}
  mint operator+=(ll x){ return set(_num + (x % _mod)); }
  mint operator-=(ll x){ return set(_num - (x % _mod)); }
  mint operator*=(ll x){ return set(_num * (x % _mod)); }
  mint operator/=(ll x){ return set(_num * imod(x));}
  mint operator+ (mint x){ return mint(_num + x._num , _mod); }
  mint operator- (mint x){ return mint(_num - x._num , _mod);}
  mint operator* (mint x){ return mint(_num * x._num , _mod); }
  mint operator/ (mint x){ return mint(_num * imod(x._num) , _mod);}
  mint operator+=(mint x){ return set(_num + x._num); }
  mint operator-=(mint x){ return set(_num - x._num); }
  mint operator*=(mint x){ return set(_num * x._num); }
  mint operator/=(mint x){ return set(_num * imod(x._num));}
 
  friend mint operator+(ll x,mint m){return mint(m._num + (x % m._mod) , m._mod);}
  friend mint operator-(ll x,mint m){return mint(m._num - (x % m._mod) , m._mod);}
  friend mint operator*(ll x,mint m){return mint(m._num * (x % m._mod) , m._mod);}
  friend mint operator/(ll x,mint m){return mint(m.imod(m._num) * x , m._mod);}
 
  explicit operator int() { return _num; }
 
  friend ostream& operator<<(ostream &os, const mint &x){ os << x._num; return os; }
  friend istream& operator>>(istream &is, mint &x){ll val; is>>val; x.set(val); return is;}
};
class MAT{
 private:
    int row,col;
    vector<vector<double>> _A;
    MAT set(vector<vector<double>> A){_A = A ; return *this;}
    
 public:
    MAT(){ }
    MAT(int n,int m){
        if(n<1 || m<0){cout << "err Matrix::Matrix" <<endl;exit(1);}
        row = n;
        col = m?m:n;//m=0のとき単位行列を作る
        rep(i,row){
            vector<double> a(col);
            _A.push_back(a);
            rep(j,col) _A[i][j]=0;
        }
        //  値の初期化
        if(m==0) rep(i,n) _A[i][i]=1.0;
    }
    MAT(const MAT &cp){_A=cp._A;row=cp.row;col=cp.col;}
    double* operator[] (int i){return _A[i].data();}
    MAT operator= (vector<vector<double>> x) {return set(x);}
    MAT operator+ (MAT x) {
        if(row!=x.row || col!=x.col){
            cout << "err Matrix::operator+" <<endl;
            cout << "  not equal matrix size" <<endl;
            exit(0);
        }
        MAT r(row, col);
        rep(i,row) rep(j,col) r[i][j]=_A[i][j]+x[i][j];
        return r;
    }
    MAT operator- (MAT x) {
        if(row!=x.row || col!=x.col){
            cout << "err Matrix::operator-" <<endl;
            cout << "  not equal matrix size" <<endl;
            exit(0);
        }
        MAT r(row, col);
        rep(i,row) rep(j,col) r[i][j]=_A[i][j]-x[i][j];
        return r;
    }
    MAT operator* (MAT x) {
        if(col!=x.row){
            cout << "err Matrix::operator*" <<endl;
            cout << "  not equal matrix size" <<endl;
            exit(0);
        }
        MAT r(row, x.col);
        rep(i,row) rep(j,x.col) rep(k,col) r[i][j]+=_A[i][k]*x[k][j];
        return r;
    }
    MAT operator/ (double a){
        MAT r(row,col);
        rep(i,row) rep(j,col) r[i][j]=_A[i][j]/a;
        return r;
    }
    MAT operator^ (ll n){
        if(row!=col){
            cout << "err Matrix::operator^" <<endl;
            cout << "  not equal matrix size" <<endl;
            exit(0);
        }
        MAT r(row,0),A=*this;
        while(n){
            if(n&1) r *= A;
            A*=A;
            n>>=1;
        }
        return r;
    }
    MAT operator+= (MAT x) {
        if(row!=x.row || col!=x.col){
            cout << "err Matrix::operator+=" <<endl;
            cout << "  not equal matrix size" <<endl;
            exit(0);
        }
        MAT r(row, col);
        rep(i,row) rep(j,col) r[i][j]=_A[i][j]+x[i][j];
        return set(r._A);
    }
    MAT operator-= (MAT x) {
        if(row!=x.row || col!=x.col){
            cout << "err Matrix::operator-=" <<endl;
            cout << "  not equal matrix size" <<endl;
            exit(0);
        }
        MAT r(row, col);
        rep(i,row) rep(j,col) r[i][j]=_A[i][j]-x[i][j];
        return set(r._A);
    }
    MAT operator*= (MAT x) {
        if(col!=x.row){
            cout << "err Matrix::operator*" <<endl;
            cout << "  not equal matrix size" <<endl;
            exit(0);
        }
        MAT r(row, x.col);
        rep(i,row) rep(j,x.col) rep(k,col) r[i][j]+=_A[i][k]*x[k][j];
        return set(r._A);
    }
    MAT operator/=(double a){
        MAT r(row,col);
        rep(i,row) rep(j,col) r[i][j]=_A[i][j]/a;
        return r;
    }
 
    friend MAT operator* (double n,MAT x){
        MAT r(x.row,x.col);
        rep(i,x.row) rep(j,x.col) r[i][j]=n*x[i][j];
        return r;
    }
    friend MAT operator* (MAT x,double n){
        MAT r(x.row,x.col);
        rep(i,x.row) rep(j,x.col) r[i][j]=n*x[i][j];
        return r;
    }
    explicit operator vector<vector<double>>(){return _A;}
    friend ostream &operator<<(ostream &os,const MAT &x){ rep(i,x.row) rep(j,x.col) os<<x._A[i][j]<<" \n"[j==x.col-1]; return os;}
    
    int size_row(){return row;}
    int size_col(){return col;}
    MAT transpose(){
        MAT r(col,row);
        rep(i,col) rep(j,row) r[i][j]=_A[j][i];
        return r;
    }
};
class Factorial{//階乗とその逆元を求めて計算に利用するクラス
 private:
    vector<int> fac;
    vector<int> ifac;
 public:
    Factorial(int N){
        fac.push_back(1);
        rep(i,N) fac.push_back(fac[i]*(i+1)%mod);
        ifac.resize(N+1);
        ifac[N]=m_inv(fac[N]);
        rep(i,N) ifac[N-1-i]=(ifac[N-i]*(N-i))%mod;
    }
    int fact(int a){return fac[a];}
    int ifact(int a){return ifac[a];}
    int cmb(int a,int b){
    	if(a==0&&b==0) return 1;
        if(a<b||a<0||b<0) return 0;
        int tmp =ifact(a-b)*ifact(b)%mod;
        return tmp*fac[a]%mod;
    }
    int per(int a,int b){
    	if(a==0&&b==0) return 1;
        if(a<b||a<0||b<0) return 0;
        return fac[a]*ifac[a-b]%mod;
    }
};
struct UnionFind {
    vector<int> par; // 親ノード
    UnionFind(int n = 1) { init(n);}
    void init(int n = 1) {
        par.resize(n);
        rep(i,n) par[i] = -1;
    }
    int root(int x) {
        if (par[x] <0) return x;
        else return par[x] = root(par[x]);      
    }
    int size(int x){ return -par[root(x)];}
    bool issame(int x, int y) {return root(x)==root(y);}
    bool connect(int x,int y) {
        x = root(x); y = root(y);
        if (x == y) return false;
        if (size(x) < size(y)) swap(x, y);
        par[x] += par[y];
        par[y] = x;
        return true;
	}
};

struct edge{int from,to,cost;
	void push(int a,int b,int c){
        from=a;to=b;cost=c;
    }
    bool operator<(const edge& y) const{
        if(cost!=y.cost) return cost<y.cost;
        else if(to!=y.to) return to<y.to;
        else return from<y.from;}
    bool operator>(const edge& y) const{
        if(cost!=y.cost) return cost>y.cost;
        else if(to!=y.to) return to>y.to;
        else return from>y.from;}
    bool operator==(const edge& y) const{return (from==y.from&&to==y.to&&cost==y.cost);}
};
class Graph{
private:
	int N,start,end;
	int inf=1LL<<40;
	vector<edge> e;
	vector<vector<int>> dist;
	vector<map<int,int>> graph;
	int log2_n = 0;
    std::vector<std::vector<int>> parent;
    std::vector<int> depth;
public:
	int diameter;
	Graph(int n){
		N=n;
		dist.resize(N);
		diameter=0;
	}
	Graph(const Graph &cp){dist=cp.dist;e=cp.e;N=cp.N;}
	//グラフの操作--------------------------
	void push(int a,int b,int c){
		e.push_back((edge){a,b,c});
	}
	void reverse(){
		rep(i,e.size()) swap(e[i].from,e[i].to);
	}
	void undirect(){
		int m=e.size();
		rep(i,m){
			push(e[i].to,e[i].from,e[i].cost);
		}
	}
	bool gmat(){
		graph.clear();
		graph.resize(N);
		rep(i,e.size()) graph[e[i].from][e[i].to]=e[i].cost;
		return true;
	}
	//グラフの入力----------------------------
	void load(int M){
		rep(i,M){
			int a,b;
			cin>>a>>b;a--;b--;
			push(a,b,1);
		}
	}
	void wload(int M){
		e.resize(M);
		rep(i,M){
			int a,b,c;
			cin>>a>>b>>c;a--;b--;
			push(a,b,c);
		}
	}
	
	//グラフの出力------------------------
	int size(){return N;}
	void out(){
		rep(i,e.size()) cout<<e[i].from+1<<" "<<e[i].to+1<<endl;
	}
	void wout(){rep(i,e.size()) cout<<e[i].from+1<<" "<<e[i].to+1<<" "<<e[i].cost<<endl;}
	int distance(int a,int b){return dist[a][b];}
	//グラフアルゴリズム-------------------
	int treeDFS(int i,int d,vector<bool> used,int &ver){
		if(diameter<d){
			diameter=d;
			ver=i;
		}
		used[i]=true;
		int ret=0;
		itr(j,graph[i]){
			int v=j->first;
			if(used[v]) continue;
			ret=treeDFS(v,j->second+d,used,ver);
		}
		used[i]=false;
		return ret;
	}
	P getDiameter(){
		gmat();
		vector<bool> used(N,false);
		treeDFS(0,0,used,end);
		treeDFS(end,0,used,start);
		return P(start,end);
	}
	//----------------------------------------------
	void bfs(int s){
		dist[s].resize(N,inf);
		gmat();
		queue<int> que;
		que.push(s);
		dist[s][s]=0;
		while(!que.empty()){
			int u=que.front();que.pop();
			itr(i,graph[u]){
				int v=i->first;
				if(dist[s][v]!=inf) continue;
				que.push(v);dist[s][v]=dist[s][u]+(i->second);
			}
		}
	}
	//最短経路------------------------
	void dijkstra(int s){
		gmat();
		dist[s].resize(N,inf);
		priority_queue<P,vector<P>,greater<>> que;
		que.push(P(s,0));
		dist[s][s]=0;
		while(!que.empty()){
			P p=que.top();que.pop();
			int u=p.first;
			if(dist[s][u]<p.second) continue;
			itr(i,graph[u]){
				int v=i->first;
				int alt=dist[s][u]+(i->second);
				if(dist[s][v]>alt){
					dist[s][v]=alt;
					que.push(P(v,alt));
				}
			}
		}
	}
	void shortest_path(){
		rep(i,N) dist[i].resize(N,inf);
		rep(i,e.size()) dist[e[i].from][e[i].to]=e[i].cost;
		rep(k,N) rep(i,N) rep(j,N){
			dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
		}
	}
	void bellman(int s){
		dist[s].resize(N,inf);
		dist[s][s]=0;
		rep(i,N-1) rep(j,e.size()){
			dist[s][e[j].to]=min(dist[s][e[j].from]+e[j].cost,dist[s][e[j].to]);
		}
	}
	bool nloop(int s,int t){
		bellman(s);
		vector<bool> negative(N,false);
		rep(i,N) rep(j,e.size()){
			if(dist[s][e[j].to]>dist[s][e[j].from]+e[j].cost){
				dist[s][e[j].to]=dist[s][e[j].from]+e[j].cost;
				negative[e[j].to]=true;
			}
			if(negative[e[j].from]) negative[e[j].to]=true;
		}
		if(negative[t]) return true;
		else return false;
	}
	//------------------------------
	//最小全域木------------------
	int prim(){
		gmat();
		vector<bool> used(N,false);
		priority_queue<P,vector<P>,greater<>> que;
		que.push(P(0,0));
		int ret=0;
		while(!que.empty()){
			P p=que.top();que.pop();
			int u=p.second;
			if(used[u]) continue;
			used[u]=true;
			ret+=p.first;
			itr(i,graph[u]) que.push(P(i->second,i->first));
		}
		return ret;
	}
	Graph kruskal(){
		Graph G(N);
		sort(All(e));
		UnionFind uni(N);
		rep(i,e.size()){
			if(uni.connect(e[i].from,e[i].to)){
				G.push(e[i].from,e[i].to,e[i].cost);
			}
		}
		return G;
	}
	//最小共通祖先----------------------------
	void lcadfs(int v, int p, int d) {
        parent[0][v] = p;
        depth[v] = d;
        itr(j,graph[v]) {
            if (j->first != p) lcadfs(j->first, v, d + 1);
        }
    }
	int lca(int root){
		gmat();
        int n=N,log2_n=log2(n)+1;
        parent.resize(log2_n,vector<int>(n));
        depth.resize(n);
        lcadfs(root, -1, 0);
        rep(k,log2_n-1) {
            rep(v,N) {
                if (parent[k][v] < 0)
                    parent[k + 1][v] = -1;
                else
                    parent[k + 1][v] = parent[k][parent[k][v]];
            }
        }   
    }
    int get(int u, int v) {
        if (depth[u] > depth[v]) std::swap(u, v);
        rep(k,log2_n) {
            if ((depth[v] - depth[u]) >> k & 1) {
                v = parent[k][v];
            }
        }
        if (u == v) return u;
        for (int k = log2_n - 1; k >= 0; k--) {
            if (parent[k][u] != parent[k][v]) {
                u = parent[k][u];
                v = parent[k][v];
            }
        }
        return parent[0][u];
    }
    void main();
};
class Sosu{
 private:
    vector<int> Prime_Number;
 public:
    Sosu(int N){
        set<int> arr;
        rep(i,N-1)  arr.insert(i+2);
        while(int n=*arr.begin()){
            if(n>sqrt(N)) break;
            Prime_Number.push_back(n);
            rep(i,1,N/n+1) arr.erase(n*i);
        }
        itr(it,arr) Prime_Number.push_back(*it);
    }
    int operator[](int i){return Prime_Number[i];}
    int size(){return Prime_Number.size();}
    bool isPrime(int q){return binary_search(All(Prime_Number),q);}
};
class Divisor{
  private:
    set<int> factorize;
    vector<int> F;
    vector<P> pfactorize;
    int sz;
  public:
    Divisor(int N){
		Sosu p(Sqrt(N)+1);
    	rep(i,p.size()){
    		pfactorize.push_back(P(p[i],0));
    		while(N%p[i]==0){
    			N/=p[i];
    			pfactorize.back().second++;
    		}
    		if(pfactorize.back().second==0){ 
    			pfactorize.pop_back();
    		}
    	}
    	if(N>1) pfactorize.push_back(P(N,1));
    	sz=1;
    	rep(i,pfactorize.size()){ 
    		sz*=pfactorize[i].second+1;
    	}
    	init(0,1);
    	itr(i,factorize) F.push_back(*i);
    }
    void init(int i,int res){
    	if(i==pfactorize.size()){
    		factorize.insert(res);
    		return;
    	}
    	rep(j,pfactorize[i].second+1){
    		init(i+1,res*npow(pfactorize[i].first,j));
    	}
    	return;
    }
    int size(){return sz;}
    vector<P> pfac(){return pfactorize;}
    int operator[](int k){
    	return F[k];
    }
};
signed main(){
	int n;cin>>n;
	int ans=1;
	map<int,int> mp;
	rep(i,n){
		Divisor d(i+1);
		vector<P> a= d.pfac();
		rep(j,a.size()) mp[a[j].first]+=a[j].second;
	}
	itr(i,mp) {
		ans*=i->second+1;
		ans%=mod;
	}
	cout<<ans<<endl;
}

void Graph::main(){
	
}


Measured memory_bytes: 256