// 5/15
// ANT2-3-8. 重複数え合わせ
// 類題
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using P = pair<int, int>;
using Graph = vector<vector<int>>;

const int mod = 1000000007;

struct mint {
  ll x; // typedef long long ll;
  mint(ll x=0):x((x%mod+mod)%mod){}
  mint operator-() const { return mint(-x);}
  mint& operator+=(const mint a) {
    if ((x += a.x) >= mod) x -= mod;
    return *this;
  }
  mint& operator-=(const mint a) {
    if ((x += mod-a.x) >= mod) x -= mod;
    return *this;
  }
  mint& operator*=(const mint a) { (x *= a.x) %= mod; return *this;}
  mint operator+(const mint a) const { return mint(*this) += a;}
  mint operator-(const mint a) const { return mint(*this) -= a;}
  mint operator*(const mint a) const { return mint(*this) *= a;}
  mint pow(ll t) const {
    if (!t) return 1;
    mint a = pow(t>>1);
    a *= a;
    if (t&1) a *= *this;
    return a;
  }

  // for prime mod
  mint inv() const { return pow(mod-2);}
  mint& operator/=(const mint a) { return *this *= a.inv();}
  mint operator/(const mint a) const { return mint(*this) /= a;}
};

// combination mod prime
// https://www.youtube.com/watch?v=8uowVvQ_-Mo&feature=youtu.be&t=1619
struct combination {
  vector<mint> fact, ifact;
  combination(int n):fact(n+1),ifact(n+1) {
    assert(n < mod);
    fact[0] = 1;
    for (int i = 1; i <= n; ++i) fact[i] = fact[i-1]*i;
    ifact[n] = fact[n].inv();
    for (int i = n; i >= 1; --i) ifact[i-1] = ifact[i]*i;
  }
  mint operator()(int n, int k) {
    if (k < 0 || k > n) return 0;
    return fact[n]*ifact[k]*ifact[n-k];
  }
};

struct Sieve {  // Sieveはふるい。
    int n;  // 最大の数
    vector<int> f, primes;
    // fはふるいの結果。f[x]はxの最小の素因数が入る。f[x] == xの場合、xは素数。
    // primesは素数のリスト。

    // コンストラクタ内でSieveする。
    Sieve(int n=1):n(n), f(n + 1) {
        // ↑↑↑まず冒頭でnとfを初期化している↑↑↑

        // 0と1の場合は特殊なので、-1を入れておく。
        // あとでisPrimeがワークするように。
        f[0] = f[1] = -1;

        // エラストテネスのふるいにかけていく。
        for (ll i = 2; i <= n; ++i) {

            // f[i]が探索済みどうかを判定する。
            // f[i] > 0なら既に判定されているはず。
            if (f[i]) continue;

            // 上のifにハマらなかったら素数。
            f[i] = i;

            // 素数ならprimesにブッコむ。
            primes.push_back(i);

            // ふるいにかける。
            for (ll j = i * i; j <= n; j += i) {
                if (!f[j]) f[j] = i;
                // i = 2の時は2, 4, 6, 8...に2を入れる。
                // i = 3の時は3, 6, 9, 12...に3を入れる。
                // なお６などの公倍数の時は、書き換えない。
                // 最小の素数を入れておくことで、後のfactor関数で小さい順に並ぶようにする。（なるほど。）
            }
        }
    }

    // xが素数かどうかを判定する
    bool isPrime(int x) {
        return f[x] == x;  // ふるいにかけられたタイミングで、素数には自身と同じ数字が入っている。
    }

    // 素因数分解して、リストを返す
    vector<int> factorList(int x) {
        vector<int> res;
        while(x != 1) {
            res.push_back(f[x]);  // 自動的に小さい順になる。
            x /= f[x];
        }
        return res;
    }

    // 普通はfactorというよりも、素因数ごとに頻度を集計したものが欲しいので...by snukeさん。
    // https://youtu.be/UTVg7wzMWQc?t=4518
    vector<P> factor(int x) {
        vector<int> fl = factorList(x);  // 例えば12なら2, 2, 3のvector
        if (fl.size() == 0) return {};

        vector<P> res(1, P(fl[0], 0));
        for (int p : fl) {
            if (res.back().first == p) {
                res.back().second++;
            } else {
                res.emplace_back(p, 1);
            }
        }
        return res;
    } 
};

int main() {
    // Sieve sieve(1e8);  // 1e8まで言ったらAC。
    Sieve sieve(1e5);
    combination comb(1e7);

    int N, M;
    cin >> N >> M;

    // auto f = sieve.factor(M);
    mint ans = 1;

    // vector<P> f;
    map<int, int> mp;

    // while(M != 1) {
    rep(i, 1e5) {
        if (sieve.isPrime(i)) {
            while (M % i == 0) {
                M /= i;
                mp[i]++;
            }
        }

        if (M == 1) {
            break;
        }
    }

    if (M != 1 && M == M) {
        mp[M]++;
    }

    // }

    // for (auto p : f) {
    //     printf("%dの素因数は%d個\n", p.first, p.second);
    //     ans *= comb(N + p.second - 1, p.second);
    // }
    for (auto p : mp) {
        ans *= comb(N + p.second - 1, p.second);
    }

    cout << ans.x << endl;
}


Measured memory_bytes: 157056