// Original C++ solution (slower):
#include <bits/stdc++.h>

#define FOR(i, a, b) for(int i=(int)(a); i!=(int)(b); i++)

#define RFOR(i, a, b) for(int i=(int)(a); i!=(int)(b); i--)

#define REP(i, n) FOR(i, 0, n)

using namespace std;

using ll = long long;



constexpr int mod = 1e9+7, lim = 1e5*2;



vector<pair<int, int>> v;

ll fac[lim+1], rfac[lim+1];



ll m_pow(ll x, ll n){

  if(n == 0) return 1;

  return m_pow(x*x%mod, n/2) * ((n%2)?x: 1) % mod;

}



void init_fac(){

  fac[0] = 1;

  FOR(i, 1, lim+1) (fac[i] = fac[i-1] * i) %= mod;



  rfac[lim] = m_pow(fac[lim], mod-2);

  RFOR(i, lim-1, -1) (rfac[i] = rfac[i+1] * (i+1)) %= mod;

}



void init_v(int n){

  for(int i=2; n != 1; i++){

    int cnt = 0;

    while(n % i == 0){

      cnt++;

      n /= i;

    }

    v.push_back({i, cnt});

  }

}



ll comb(ll n, ll r){

  if(n==r || r == 0) return 1;

  return (fac[n] * rfac[n-r]) % mod * rfac[r] % mod;

}



int main(){

  int n, m; cin >> n >> m;



  init_fac();

  init_v(m);



  ll ans = 1;

  REP(i, v.size()){

    if(v[i].second){

      (ans *= comb(n+v[i].second-1, v[i].second)) %= mod;

    }

  }



  cout << ans << endl; 

  

  return 0;

}


// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

#define FOR(i, a, b) for(int i=(a); i<(b); i++)

#define REP(i, n) FOR(i, 0, n)

#define all(x) (x).begin(), (x).end()

#define bit(x) (1L << (x))

using ll = long long;

using namespace std;



template<typename T>

vector<T> make_v(size_t a,T b){return vector<T>(a,b);}

 

template<typename... Ts>

auto make_v(size_t a,Ts... ts){

    return vector<decltype(make_v(ts...))>(a,make_v(ts...));

}



template <int Mod, bool IsPrime = false>

class mod_int {

    using ll = long long;



public:

    constexpr mod_int() : n(0) {}

    constexpr mod_int(int n_) : n(n_) {

        if(n >= Mod)     n %= Mod;

        else if(n < 0) n = (n % Mod + Mod) % Mod;

    }

    constexpr mod_int(ll n_) : n(n_) { n = (n + Mod) % Mod; }



    constexpr operator int() const { return n; }

    constexpr operator ll() const  { return n; }



    constexpr bool operator==(mod_int const& other) const { return n == other.n; }

    constexpr mod_int& operator+=(mod_int const& other) {

        if((n += other.n) >= Mod) n -= Mod;

        return *this;

    }

    constexpr mod_int& operator-=(mod_int const& other) {

        if((n += Mod - other.n) >= Mod) n -= Mod;

        return *this;

    }

    constexpr mod_int& operator*=(mod_int const& other) {

        n = (unsigned long long)n * other.n % Mod;

        return *this;

    }

    constexpr typename std::enable_if<IsPrime, mod_int>::type& operator/=(mod_int const& other) {

        return *this *= other.inverse();

    }

    constexpr mod_int operator+(mod_int other) const { return mod_int(*this) += other; }

    constexpr mod_int operator-(mod_int other) const { return mod_int(*this) -= other; }

    constexpr mod_int operator*(mod_int other) const { return mod_int(*this) *= other; }

    constexpr mod_int operator/(mod_int other) const { return mod_int(*this) /= other; }



    constexpr typename std::enable_if<IsPrime, mod_int>::type inverse() const {

        ll a = n, b = Mod, u = 1, v = 0;

        while(b) {

            ll t = a / b;

            a -= t * b; std::swap(a, b);

            u -= t * v; std::swap(u, v);

        }

        return mod_int(u);

    }



    friend std::istream& operator>>(std::istream& is, mod_int<Mod, IsPrime>& n) {

      is >> n.n;

      return is;  

    }



    friend std::ostream& operator<<(std::ostream& os, mod_int<Mod, IsPrime> const& n) {

        os << n.n;

        return os;

    }



private:

    ll n;

};



constexpr int default_mod = 1000000007;



template <int Mod = default_mod>

mod_int<Mod, true> fact(int n) {

    static std::vector<mod_int<Mod, true>> v = {1};

    if(n >= static_cast<int>(v.size())) {

        const int from = v.size(), to = n + 1024;

        v.reserve(to);

        for(int i = from; i < to; ++i) {

            v.push_back(v.back() * mod_int<Mod, true>(i));

        }

    }

    return v[n];

}



template <int Mod = default_mod>

mod_int<Mod, true> comb(int n, int r) { // nCr

    if(r < 0 || r > n) return 0;

    return fact<Mod>(n) / fact<Mod>(r) / fact<Mod>(n - r);

}



template <int Mod = default_mod, bool IsPrime = true>

mod_int<Mod, IsPrime> mpow(mod_int<Mod, IsPrime> x, int n) {

    if(n == 0) return mod_int<Mod, IsPrime>(1);

    return mpow(x * x, n / 2) * (n % 2 ? x : mod_int<Mod, IsPrime>(1));

}



template <int Mod = default_mod, bool IsPrime = true>

mod_int<Mod, IsPrime> mpow(int x, int n) {

  return mpow(mod_int<Mod, IsPrime>(x), n);

}



using mint = mod_int<default_mod, true>; // default



map<int, int> get_map(int n) {

    map<int, int> ret;



    for (int i = 2; n != 1; i++) {

        while (n % i == 0) {

            n /= i;

            ret[i]++;

        }

    }



    return ret;

}



int main() {

    int n, m; cin >> n >> m;



    auto mp = get_map(m);



    mint ans(1);

    for(const auto& itr : mp) {

        int t = itr.second;

        ans *= comb(t + n - 1, t);

    }



    cout << ans << endl;

    

    return 0;

}


// Fastest known solution for this problem: