{-#LANGUAGE FlexibleContexts#-}
import Control.Monad
import Control.Monad.State
import Control.Monad.Reader
import Control.Arrow
-- import Control.Comonad
import Data.Maybe
import Data.List
import Data.Bool
import Data.Fixed
import Data.Tuple
import Data.Ratio
import qualified Data.Map.Strict as M
import qualified Data.Array.IO as IA
import qualified Data.Vector as V

getI = read <$> getLine :: IO Int
getIs = map read . words <$> getLine :: IO [Int]
getD = read <$> getLine :: IO Double
getDs = map read . words <$> getLine :: IO [Double]
getInt = read <$> getLine :: IO Integer
getInts = map read . words <$> getLine :: IO [Integer]

type Row = Integer
type Col = Integer
type PointI = (Integer, Integer)
type Point = (Int, Int)

mmm = 1000000007
fact n
    | n < 1 = 1
    | True = foldr1 (*) [1..n]
ti = toInteger
fi = fromInteger
fig = fromIntegral
rf = realToFrac

(.<.) :: Integer -> Integer -> Integer
(.<.) f g -- combination
    | g < 1 || f < 1 || f < g = 1
    | True = foldr1 (*) (take (fi g) [f,f-1..]) `div` fact g
(.>.) f g --combination with repetition
    | g < 1 || f < 1 = 1
    | True = fact (f + g - 1) `div` (fact (f - 1) * fact g)
comb = (.<.)
combWp = (.>.)

unique a = unique_ (reverse . sort $ a) [] Nothing
    where
        unique_ [] arr _ = arr
        unique_ (x:xs) arr n
            | n == Just x = unique_ xs arr n
            | otherwise = unique_ xs (x:arr) $ Just x
 
zeroume keta num
    | (length . show $ num) > keta = show num
    | otherwise = do 
        let zeros = take keta $ repeat '0'
        reverse . take keta $ (reverse . show $ num) ++ zeros
 
i2b num
    | num < 2 = show num
    | otherwise = i2b_ num []
        where
            i2b_ num str
                | num == 0 = str
                | num == 1 = '1':str
                | otherwise = do
                    let next = num `div` 2
                    let this = if odd num then '1' else '0'
                    i2b_ next (this:str)

mapIncr = mapPlus 1
mapPlus n Nothing = Just n
mapPlus n a = (+) n <$> a

countIf f = length . filter f

-- 
--
--

isPrime n = do
    (max, mp, _) <- get
    return . not . isJust $ M.lookup n mp
searchPrime n = do
    (max, mp, counting) <- get
    if max < n then return counting
    else do
        res <- isPrime n
        if not res then searchPrime (n + 1)
        else do
            let newmp = foldr ($) mp . map (\x -> M.insert x True) $ take (div max n)[n, n+n..]
                newc = n:counting
            put (max, newmp, newc) >> searchPrime (n + 1)
enumPrime max = evalState (searchPrime 2) ((max, M.empty, []))

-- ↓案の定クソ遅い
-- searchPrime2 max arr primes = do
--     if a > max then primes
--     else let newa = filter (\x -> mod x a /= 0) arr in searchPrime2 max newa (a:primes)
--     where a = head arr
-- sp n = searchPrime2 n [2..] []

enumDivisor :: Int -> [Int]
enumDivisor 2 = [1,2]
enumDivisor n = do
    let sqrted = floor $ sqrt (fromIntegral n)
        smaller = filter (\x -> mod n x == 0) [1..sqrted]
        bigger = reverse $ map (div n) smaller
    if head bigger == sqrted then smaller ++ (init bigger)
    else smaller ++ bigger


factoring :: (Integral a ) => a -> [(a, Integer)]
factoring n = evalState process (n, 2, M.empty)
    where
        process = do
            get >>= proc
            where
                proc (n, divisor, mp)
                    | n <= 1 = return $ M.toList mp
                    | mod n divisor == 0 = put (div n divisor, divisor, M.alter mapIncr divisor mp) >> process
                    | True = put (n, divisor + 1, mp) >> process

main = do
    [n, m] <- getIs
    let factors = factoring m
    putStrLn . show . foldr (\x y -> mod (x * y) mmm) 1 $ map (\(_, x) -> let z = fi x in (ti (z + n - 1)) .<. (ti z)) factors




Measured memory_bytes: 508