#include <bits/stdc++.h>
using namespace std;

// macros
#define rep(i, n) for(ll i = 0; i < (ll)(n); i++)
#define rrep(i, n) for(ll i = (ll)(n) - 1; i >= 0; i--)
#define trep(i, n) for(ll i = 0; i <= (ll)(n); i++)
#define mfor(i, s, t) for(ll i = (ll)(s); i < (ll)(t); i++)
#define tfor(i, s, t) for(ll i = (ll)(s); i <= (ll)(t); i++)

// type alias
using ll = long long;

// const value
const ll mod = 1000000007;
const ll inf = 1000000000000LL;

// meta programming
template<typename F> class res_type_;
template<typename R, typename... Args> class res_type_<R(*)(Args...)> {
public:
	using type = R;
};
template<typename R, typename... Args> class res_type_<function<R(Args...)>> {
public:
	using type = R;
};
template<typename F> class res_type_ {
public:
	using type = typename res_type_<decltype(+declval<F>())>::type;
};
template<typename F> using res_type = typename res_type_<F>::type;

template<typename V> class mem_type_;
template<typename T> class mem_type_<vector<T>> {
public:
	using type = T;
};
template<typename V> using mem_type = typename mem_type_<V>::type;

// for convenience
template<typename K, typename V> class order_tag {
public:
	K key;
	V value;
	order_tag(K k, V v): key(k), value(v) {}
	bool operator==(const order_tag& o) const {
		return key == o.key;
	}
	bool operator!=(const order_tag& o) const {
		return key != o.key;
	}
	bool operator<(const order_tag& o) const {
		return key < o.key;
	}
	bool operator<=(const order_tag& o) const {
		return key <= o.key;
	}
	bool operator>(const order_tag& o) const {
		return key > o.key;
	}
	bool operator>=(const order_tag& o) const {
		return key >= o.key;
	}
};
template<typename K, typename V> auto tagging(const K& k, const V& v) {
	return order_tag<K, V>(k, v);
}

// functions for functional programming
auto v_range(ll n) {
	vector<ll> ret;
	ret.reserve(n);
	rep(i, n) {
		ret.push_back(i);
	}
	return ret;
}
template<typename F> auto v_init(ll n, F f) {
	vector<res_type<F>> ret;
	ret.reserve(n);
	rep(i, n) {
		ret.push_back(f(i));
	}
	return ret;
}
template<typename T> auto v_rev(const vector<T>& v) {
	vector<T> ret;
	ret.reserve(v.size());
	rrep(i, v.size()) {
		ret.push_back(v[i]);
	}
	return ret;
}
template<typename T, typename F> void v_iter(const vector<T>& v, F f) {
	for(const auto& i: v) {
		f(i);
	}
}
template<typename T, typename F> auto v_map(const vector<T>& v, F f) {
	vector<res_type<F>> ret;
	ret.reserve(v.size());
	for(const auto& i: v) {
		ret.push_back(f(i));
	}
	return ret;
}
template<typename T, typename R, typename F> auto v_fold(const vector<T>& v, R r, F f) {
	for(const auto& i: v) {
		r = f(r, i);
	}
	return r;
}
template<typename T, typename F> auto v_filter(const vector<T>& v, F f) {
	vector<T> ret;
	for(const auto& i: v) {
		if(f(i)) {
			ret.push_back(i);
		}
	}
	return ret;
}
template<typename T, typename F> auto v_fmap(const vector<T>& v, F f) {
	vector<mem_type<res_type<F>>> ret;
	for(const auto& i: v) {
		for(const auto& j: f(i)) {
			ret.push_back(j);
		}
	}
	return ret;
}
template<typename T, typename F> bool v_forall(const vector<T>& v, F f) {
	for(const auto& i: v) {
		if(!f(i)) {
			return false;
		}
	}
	return true;
}
template<typename T, typename F> bool v_exists(const vector<T>& v, F f) {
	for(const auto& i: v) {
		if(f(i)) {
			return true;
		}
	}
	return false;
}
template<typename T, typename F> T v_find(const vector<T>& v, F f) {
	for(const auto& i: v) {
		if(f(i)) {
			return i;
		}
	}
	assert(false);
}
template<typename T, typename F> ll v_find_index(const vector<T>& v, F f) {
	rep(i, v.size()) {
		if(f(v[i])) {
			return i;
		}
	}
	return -1;
}
template<typename T> auto v_with_index(const vector<T>& v) {
	vector<pair<ll, T>> ret;
	ret.reserve(v.size());
	rep(i, v.size()) {
		ret.push_back(make_pair(i, v[i]));
	}
	return ret;
}
template<typename T, typename U> auto v_zip(const vector<T>& t, const vector<U>& u) {
	assert(t.size() == u.size());
	vector<pair<T, U>> ret;
	ret.reserve(t.size());
	rep(i, t.size()) {
		ret.push_back(make_pair(t[i], u[i]));
	}
	return ret;
}
template<typename T, typename U> auto v_unzip(const vector<pair<T, U>>& v) {
	vector<T> t;
	vector<U> u;
	t.reserve(v.size());
	u.reserve(v.size());
	for(const auto& i: v) {
		t.push_back(i.first);
		u.push_back(i.second);
	}
	return make_pair(t, u);
}
template<typename T> auto v_with_next(const vector<T>& v) {
	assert(v.size() >= 2);
	vector<pair<T, T>> ret;
	ret.reserve(v.size() - 1);
	rep(i, v.size() - 1) {
		ret.push_back(make_pair(v[i], v[i + 1]));
	}
	return ret;
}
template<typename T> auto v_with_next_circle(const vector<T>& v) {
	assert(v.size() >= 2);
	vector<pair<T, T>> ret;
	ret.reserve(v.size());
	rep(i, v.size() - 1) {
		ret.push_back(make_pair(v[i], v[i + 1]));
	}
	ret.push_back(make_pair(v.back(), v[0]));
	return ret;
}
template<typename T> T v_sum(const vector<T>& v) {
	assert(!v.empty());
	T now = v[0];
	mfor(i, 1, v.size()) {
		now = now + v[i];
	}
	return now;
}
template<typename T> T v_min(const vector<T>& v) {
	assert(!v.empty());
	T now = v[0];
	mfor(i, 1, v.size()) {
		if(v[i] < now) {
			now = v[i];
		}
	}
	return now;
}
template<typename T> pair<T, ll> v_min_index(const vector<T>& v) {
	assert(!v.empty());
	T now = v[0];
	ll ind = 0;
	mfor(i, 1, v.size()) {
		if(v[i] < now) {
			now = v[i];
			ind = i;
		}
	}
	return make_pair(now, ind);
}
template<typename T> T v_max(const vector<T>& v) {
	assert(!v.empty());
	T now = v[0];
	mfor(i, 1, v.size()) {
		if(now < v[i]) {
			now = v[i];
		}
	}
	return now;
}
template<typename T> pair<T, ll> v_max_index(const vector<T>& v) {
	assert(!v.empty());
	T now = v[0];
	ll ind = 0;
	mfor(i, 1, v.size()) {
		if(now < v[i]) {
			now = v[i];
			ind = i;
		}
	}
	return make_pair(now, ind);
}
template<typename T, typename F> auto v_group_by(const vector<T>& v, F f) {
	vector<order_tag<res_type<F>, T>> m;
	m.reserve(v.size());
	for(const auto& i: v) {
		m.push_back(tagging(f(i), i));
	}
	sort(m.begin(), m.end());
	vector<pair<res_type<F>, vector<T>>> ret;
	for(const auto& i: m) {
		if(ret.empty() || ret.back().first < i.key) {
			ret.push_back(make_pair(i.key, vector<T>{i.value}));
		}
		else {
			ret.back().second.push_back(i.value);
		}
	}
	return ret;
}

// input
template<typename T, typename U> istream& operator>>(istream& is, pair<T, U>& p) {
	is >> p.first >> p.second;
	return is;
}
template<typename K, typename V> istream& operator>>(istream& is, order_tag<K, V>& p) {
	is >> p.key >> p.value;
	return is;
}
template<typename T> T read() {
	T ret;
	cin >> ret;
	return ret;
}
template<typename T> vector<T> read_many(int n) {
	vector<T> ret;
	ret.reserve(n);
	rep(i, n) {
		ret.push_back(read<T>());
	}
	return ret;
}

// output
template<typename T, typename U> ostream& operator<<(ostream& os, const pair<T, U>& p) {
	os << p.first << " " << p.second;
	return os;
}
template<typename K, typename V> ostream& operator<<(ostream& os, const order_tag<K, V>& p) {
	os << p.key << " " << p.value;
	return os;
}
template<typename T> ostream& operator<<(ostream& os, const vector<T>& v) {
	rep(i, v.size()) {
		if(i > 0) {
			os << " ";
		}
		os << v[i];
	}
	return os;
}

int main() {
	ll n = read<ll>();
	vector<ll> dp(40, 0);
	dp[0] = 1;
	rep(_, n) {
		vector<ll> nex(40, 0);
		rep(i, 40) {
			mfor(j, i, 40) {
				nex[j] += dp[i];
			}
		}
		rep(i, 40) {
			dp[i] = nex[i] % mod;
		}
	}
	ll m = read<ll>();
	ll ans = 1;
	ll now = m;
	for(int i = 2; i * i <= m; i++) {
		ll k = 0;
		while(now % i == 0) {
			now /= i;
			k++;
		}
		ans = ans * dp[k] % mod;
	}
	if(now != 1) {
		ans = ans * dp[1] % mod;
	}
	cout << ans << endl;
	return 0;
}


Measured memory_bytes: 256