use core::ops::Bound::Excluded;
use core::ops::Bound::Included;
use std::collections::BTreeSet;
use std::cmp::Ordering;
use std::fmt::Debug;

fn read_line() -> String {
    let mut buffer = String::new();
    std::io::stdin().read_line(&mut buffer).expect("No Line");
    buffer
}
fn read_lines<R, T: Fn(&str)->R> (count: usize, transformer: T) -> Vec<R> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(transformer(buffer.trim()));
        buffer.clear();
    }
    vec
}
fn read_value<T: std::str::FromStr>() -> T {
    read_line().trim().parse().ok().unwrap()
}
fn read_values<T: std::str::FromStr>() -> Vec<T> {
    read_line().trim().split(' ').map(|x| x.parse().ok().expect("Can't Parse")).collect::<Vec<T>>()
}
fn read_tabulate<T: std::str::FromStr>(count: usize) -> Vec<T> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(buffer.trim().parse().ok().expect("Can't Parse"));
        buffer.clear();
    }
    vec
}
macro_rules! define {
    () => {};
    ($($token:tt)*) => {
        let mut iter = read_values::<String>().into_iter();
        define_iter!(iter, $($token)*);
    };
}
macro_rules! define_iter {
    ($iter:expr) =>{};
    ($iter:expr,) =>{};
    ($iter:expr, $id:ident:$t:tt $($tail:tt)*) => {
        let $id: $t = $iter.next().unwrap().parse().ok().expect("Can't Parse");
        define_iter!($iter, $($tail)*);
    };
    ($iter:expr, mut $id:ident:$t:tt $($tail:tt)*) => {
        let mut $id: $t = $iter.next().unwrap().parse().ok().expect("Can't Parse");
        define_iter!($iter, $($tail)*)
    };
}
macro_rules! freeze {
    ($($id:ident), *) => {
        $(let $id = $id;)*
    };
}
struct KeyValue<K, V> {
    key: K,
    value: V
}
impl <K: PartialOrd, V> PartialEq for KeyValue<K, V> {
    fn eq(&self, other: &Self) -> bool {
        self.key.eq(&other.key)
    }
}
impl <K: PartialOrd, V> Eq for KeyValue<K, V> {}
impl <K: PartialOrd, V> PartialOrd for KeyValue<K, V> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.key.partial_cmp(&other.key)
    }
}
impl <K: PartialOrd, V> Ord for KeyValue<K, V> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.key.partial_cmp(&other.key).ok_or("Can't Compare").unwrap()
    }
}
const MOD: i64 = 1000000007i64;

fn primes(upper_limit: usize) -> Vec<usize> {
    let mut is_prime = vec![true; upper_limit + 1];
    for i in (4 ..= upper_limit).step_by(2) {
        is_prime[i] = false;
    }
    let mut p = 3usize;
    while p * p <= upper_limit {
        if is_prime[p] {
            for j in (p * 3 ..= upper_limit).step_by(p << 1) {
                is_prime[j] = false;
            }
        }
        p += 2;
    }
    let mut result = Vec::new();
    for i in 2 ..= upper_limit {
        if is_prime[i] {
            result.push(i);
        }
    }
    result
}
fn count_factor(n: usize, p: usize) -> usize {
    match n {
        0 => 0,
        _ => n / p + count_factor(n / p, p),
    }
}
fn main() {
    define! {
        n: usize
    }
    let prime = primes(n);
    let exp = prime.iter().map(|&p| count_factor(n, p));
    let result = exp.fold(1i64, |acc, e| acc * (e as i64 + 1) % MOD);
    println!("{}", result);
}

Measured memory_bytes: 2140