#include <bits/stdc++.h>
template <int n>
class nRing {
 public:
  nRing() : x(0) {}
  nRing(int x) {
    x = x % n;
    if (x < 0) x += n;
    this->x = x;
  }
  nRing(long long x) {
    x = x % n;
    if (x < 0) x += n;
    this->x = x;
  }
  nRing& operator+=(const nRing& other) {
    x += other.x;
    if (x >= n) x -= n;
    return *this;
  }
  nRing& operator-=(const nRing& other) {
    x -= other.x;
    if (x < 0) x += n;
    return *this;
  }
  nRing& operator*=(const nRing& other) {
    x = ((long long)(x)*other.x) % n;
    return *this;
  }
  nRing operator-() {
    if (x == 0) return nRing(0);
    return nRing(n - x);
  }
  nRing operator++(int) {
    if (x + 1 < n) return nRing(x + 1);
    return nRing(0);
  }
  nRing operator--(int) {
    if (x - 1 < 0) return nRing(n - 1);
    return nRing(x - 1);
  }
  nRing& operator++() {
    if (x + 1 < n)
      x = x + 1;
    else
      x = 0;
    return *this;
  }
  nRing& operator--() {
    if (x - 1 < 0)
      x = n - 1;
    else
      x = x - 1;
    return *this;
  }
  friend nRing operator+(nRing lhs, const nRing& rhs) {
    lhs += rhs;
    return lhs;
  }
  friend nRing operator-(nRing lhs, const nRing& rhs) {
    lhs -= rhs;
    return lhs;
  }
  friend nRing operator*(nRing lhs, const nRing& rhs) {
    lhs *= rhs;
    return lhs;
  }
  friend std::ostream& operator<<(std::ostream& os, const nRing& m) {
    os << m.x;
    return os;
  }
  friend std::istream& operator>>(std::istream& is, nRing& m) {
    is >> m.x;
    return is;
  }
  explicit operator int() const { return x; }

 protected:
  int x;
};
template <int n>
class nField : public nRing<n> {
 public:
  nField() : nRing<n>() {}
  nField(int x) : nRing<n>(x) {}
  nField(const nRing<n>& ring) : nRing<n>(ring) {}
  nField& operator/=(const nField& other) {
    if (other.x == 0) throw("Division by zero.");
    this->x = ((long long)(this->x) * other.getInverse()) % n;
    return *this;
  }
  friend nField operator/(nField lhs, const nField& rhs) {
    lhs /= rhs;
    return lhs;
  }

 private:
  long long getInverse() const {
    long long a, b;
    long long d = gcdExtended(this->x, n, a, b);
    if (d != 1) throw("Not inversible.");
    if (a < 0) a += n;
    return a;
  }
  long long gcdExtended(long long z, long long y, long long& a,
                        long long& b) const {
    if (z == 0) {
      a = 0;
      b = 1;
      return y;
    }
    long long d = gcdExtended(y % z, z, b, a);
    a -= (y / z) * b;
    return d;
  }
};
using namespace std;
const int MOD = 1e9 + 7;
const int MAXN = 1e6 + 10;
vector<int> divi[MAXN], adj[MAXN];
int longestPath[MAXN], isRoot[MAXN];
nField<MOD> fact[MAXN], inv[MAXN], dp[MAXN][2];
bool vis[MAXN][2];
int n;
inline nField<MOD> variations(int a, int b) { return fact[a] * inv[a - b]; }
nField<MOD> go(int y, int rem, int iter) {
  if (y == 1) return 1;
  if (vis[y][iter]) return dp[y][iter];
  nField<MOD> res;
  for (int x : adj[y]) {
    int m = n / x - n / y;
    res += m * variations(rem - 1, m - 1) * go(x, rem - m, iter);
  }
  vis[y][iter] = true;
  return dp[y][iter] = res;
}
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cin >> n;
  fact[0] = inv[0] = 1;
  for (int i = 1; i <= n; i++) {
    fact[i] = fact[i - 1] * i;
    inv[i] = 1 / fact[i];
  }
  for (int i = 1; i <= n; i++)
    for (int j = 2 * i; j <= n; j += i) divi[j].push_back(i);
  int mxlen = 0;
  for (int i = 1; i <= n; i++) {
    longestPath[i] = 1;
    for (int j : divi[i])
      longestPath[i] = max(longestPath[i], 1 + longestPath[j]);
    for (int j : divi[i])
      if (longestPath[j] + 1 == longestPath[i]) adj[i].push_back(j);
    mxlen = max(mxlen, longestPath[i]);
  }
  nField<MOD> res;
  vector<int> roots;
  for (int i = 1; i <= n; i++)
    if (longestPath[i] == mxlen) roots.push_back(i);
  for (int i = 0; i < roots.size(); i++) res += go(roots[i], n - 1, i);
  cout << res << endl;
  return 0;
}
