#include <bits/stdc++.h>

#define REP(i, n) for(decltype(n) i = 0; i < n; i++)

#define ALL(c)   c.begin(), c.end()
#define SORT(c)  std::sort(ALL(c))
#define RSORT(c) std::sort(ALL(c), std::greater<decltype(c)::value_type>())

using namespace std;
using ll = long long;

const int MOD  = (int)1e9 + 7;
const int INF  = (int)1e9 + 1;
const ll  LINF = (long long)1e18 + 1;

class PrimeNumberCalculator {
    using ull = unsigned long long;
public:
    PrimeNumberCalculator() = default;
    PrimeNumberCalculator(const ull& n_max) :
        list_(generate(std::sqrt(n_max))),
        n_max_(n_max),
        list_is_init_(true) { }

    /**
     *  素数を生成する
     *  @n_max:  値の最大値
     *  @Return: n_max以下の素数
     */
    std::vector<ull> generate(const ull& n_max) const {
        std::vector<uint> table(n_max + 1, 0);
        std::vector<ull> list;
        for(ull i = 2; i <= n_max; i++) {
            if(table[i] == 0) {
                list.push_back(i);
                for(uint j = i; j <= n_max; j+=i) {
                    table[j] = 1;
                }
            }
        }
        return list;
    }

    /**
     *  素数であるかどうかを判定する
     *  @n:      入力
     *  @Return: 素数であればtrueを返す
     */
    bool check(const ull& n) {
        validate(n);
        ull n_max = std::sqrt(n);
        for(const auto& v : list_) {
            if(n_max < v) {
                break;
            }
            else if(n % v == 0) {
                return false;
            }
        }
        return true;
    }

    /**
     *  素因数分解を行い、底とその冪指数を返す
     *  @n:      入力
     *  @Return: key :: 底(素数), value :: 冪指数
     */
    std::map<ull, ull> generatePrimeFactorizationMap(ull n) {
        validate(n);
        std::map<ull, ull> prime_cnt_map;
        ull n_max = std::sqrt(n);
        for(const auto& v : list_) {
            if(n_max < v) {
                break;
            }
            while(n % v == 0) {
                n /= v;
                auto itr = prime_cnt_map.find(v);
                if(itr != prime_cnt_map.end()) {
                    itr->second++;
                }
                else {
                    prime_cnt_map.insert(make_pair(v, 1));
                }
            }
        }
        if(1 < n) {
            prime_cnt_map.insert(make_pair(n, 1));
        }
        return prime_cnt_map;
    }

    /**
     *  約数の個数を返す
     *  @n:      入力
     *  @Return: 約数の個数
     */
    ull calcNumOfDivisor(ull n) {
        ull  num = 1;
        auto map = generatePrimeFactorizationMap(n);
        for(const auto& v : map) {
            num *= (v.second + 1);
        }
        return num;
    }

    /**
     *  約数の総和を返す
     *  @n:      入力
     *  @Return: 約数の総和
     */
    ull calcSumOfDivisor(ull n) {
        ull sum   = 1;
        auto map = generatePrimeFactorizationMap(n);
        for(const auto& v : map) {
            ull t     = 1;
            ull t_sum = 1;
            for(ull i = 0; i < v.second; i++) {
                t     *= v.first;
                t_sum += t;
            }
            sum *= t_sum;
        }
        return sum;
    }

private:
    std::vector<ull> list_;
    ull              n_max_;
    bool             list_is_init_;

    /**
     *  前計算で導出しているテーブルのvalidateを行う
     *  @n:      対象の入力
     *  @Return: void
     */
    void validate(const ull& n) {
        if(n_max_ < n || !list_is_init_) {
            list_         = generate(std::sqrt(n));
            n_max_        = n;
            list_is_init_ = true;
        }
    }
};

class CombinationCalcurator {
    using ull = unsigned long long;
public:
    /**
     *  組み合わせの数を求めるクラス
     *  @n_max: ${}_n C_r$ における ${}_n$ の最大値
     *  @mod:   組み合わせの数に対して取るMODの値
     */
    CombinationCalcurator(const ull& n_max,
                          const ull& mod = 0):
        m_(mod),
        fact_(n_max + 1, 0),
        inv_fact_(n_max + 1, 0),
        inv_(n_max + 1, 0) {
        std::fill(fact_.begin(), fact_.begin() + 2, 1);
        std::fill(inv_fact_.begin(), inv_fact_.begin() + 2, 1);
        std::fill(inv_.begin(), inv_.begin() + 2, 1);
        for(ull i = 2; i <= n_max; i++) {
            fact_[i]     = (fact_[i - 1] * i) % m_;
            inv_[i]      = m_ - inv_[m_ % i] * (m_ / i) % m_;
            inv_fact_[i] = inv_fact_[i - 1] * inv_[i] % m_;
        }
    }

    /**
     *  ${}_n C_r$ を求める
     *  @n:      ${}_n$ の値
     *  @k:      ${}_k$ の値
     *  @Return: ${}_n C_r$
     */
    ull run(const ull& n,
            const ull& k) {
        if(n < k || (n < 0 || k < 0)) {
            return 0;
        }
        else {
            return fact_[n] * (inv_fact_[k] * inv_fact_[n - k] % m_) % m_;
        }
    }
private:
    ull m_;
    std::vector<ull> fact_;
    std::vector<ull> inv_fact_;
    std::vector<ull> inv_;
};

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);

    int N, M;
    std::cin >> N >> M;

    CombinationCalcurator comb(150000, MOD);
    PrimeNumberCalculator p(M);

    auto map = p.generatePrimeFactorizationMap(M);
    auto ans = 1LL;
    for(const auto& v : map) {
        ans *= comb.run(v.second + N - 1, v.second);
        ans %= MOD;
    }

    std::cout << ans << std::endl;

    return 0;
}


Measured memory_bytes: 3968