#include <algorithm>
#include <cmath>
#include <iostream>
#include <iterator>
#include <map>
#include <queue>
#include <unordered_map>
#include <vector>

using namespace std;

#define ll long long
#define el '\n'
#define rep(i, a, b) for (int i = a; i < b; i++)
#define repi(i, a, b) for (int i = a; i >= b; i--)
#define VI vector<int>
#define VII vector<pair<int, int>>
#define PII pair<int, int>
#define MP make_pair
// #define log(fmt, ...) printf(fmt, ##__VA_ARGS__)
#define log(fmt, ...)
// #define check(...) assert(##__VA_ARGS__)
#define check(...)

#define MODULO 1000000007
#define MAXN 100000

int fac[MAXN], fnv[MAXN];

int extgcd(int a, int b, int &x, int &y) {
    if (a == 0) {
        x = 0;
        y = 1;
        return b;
    }
    int x1, y1;
    int d = extgcd(b % a, a, x1, y1);
    x = y1 - (b / a) * x1;
    y = x1;
    return d;
}

int invmod(int a, int m) {
    int x, y;
    int g = extgcd(a, m, x, y);
    if (g != 1) {
        return -1;
    } else {
        x = (x % m + m) % m;
        return x;
    }
}

void pre_fac_fnv(int n) {
    fac[0] = 1;
    fac[1] = 1;
    fnv[1] = 1;
    fnv[0] = 1;
    rep(i, 2, n + 1) {
        fac[i] = (ll)fac[i - 1] * i % MODULO;
        fnv[i] = invmod(fac[i], MODULO);
    }
}

int add(int a, int b) {
    return ((ll)a + b) % MODULO;
}

int sub(int a, int b) {
    return ((ll)a + MODULO - b) % MODULO;
}

int mul(int a, int b) {
    return (ll)a * b % MODULO;
}

namespace my {

int div(int a, int b) {
    return (ll)a * invmod(b, MODULO) % MODULO;
}

}  // namespace my

// a * k!
int mulfac(int a, int k) {
    return (ll)a * fac[k] % MODULO;
}

// a / k!
int divfac(int a, int k) {
    return (ll)a * fnv[k] % MODULO;
}

int power(int base, int exp) {
    if (base == 0) {
        return 0;
    }
    if (exp == 0) {
        return 1;
    }
    if (exp == 1) {
        return base;
    }
    int half = power(base, exp / 2);
    if (exp % 2 == 0) {
        return mul(half, half);
    } else {
        return mul(base, mul(half, half));
    }
}

int n;
int power_cache[100001];

int power(int base) {
    if (power_cache[base] >= 0) {
        return power_cache[base];
    }
    return power_cache[base] = power(base, n);
}

// 最小数是1，最大数不超过q的n位序列总数
// 1..q的n位序列数，减去2..q的n位序列数，就是含有1的序列数
int all1(int q, int n) {
    return sub(power(q, n), power(q - 1, n));
}

// int max_q_sub_min = 0;

// 最小数是min，最大数不超过q的n位序列总数
// min..q的序列数，减去(min+1)..q的序列数，就是含有min的序列数
int all1(int min, int q, int n) {
    // max_q_sub_min = max(max_q_sub_min, q - min);
    return sub(power(q - (min - 1), n), power(q - min, n));
}

VI factors_cache[100001];
int factors_hit = 0;

VI factors(int q) {
    if (!factors_cache[q].empty()) {
        factors_hit++;
        return factors_cache[q];
    }
    VI ans;
    int limit = (int)sqrt(q);
    rep(i, 2, limit + 1) {
        if (q % i == 0) {
            ans.push_back(i);
            if (i != q / i) {
                ans.push_back(q / i);
            }
        }
    }
    ans.push_back(1);
    ans.push_back(q);
    return factors_cache[q] = ans;
}

// int k_div_min = 0;
VI min_by_k[100001];
// VI mins;
// VI ks;
#define K_SHRINK 8
int k_large = 0, k_small = 0;
int k_threshold;
int count_small_cache[100000 / K_SHRINK + 1][100000 / K_SHRINK + 1];
int k_small_hit = 0;

// min..k中可重复的选n个数且含有min的使gcd=1的方案数
int count(int min, int k) {
    // check(min <= k);
    // assert(min<=k);
    if (k > k_threshold) {
        k_large++;
    } else {
        k_small++;
        if (count_small_cache[k][min] >= 0) {
            k_small_hit++;
            return count_small_cache[k][min];
        }
    }
    // if (k == 120) {
    //     mins.push_back(min);
    // }
    // ks.push_back(k);
    if (min == 1) {
        // log("count(min=%d,k=%d,n=%d)=%d\n", min, k, n, all1(min, k, n));
        return all1(min, k, n);
    }
    // k_div_min = max(k_div_min, k / min);
    int ans = all1(min, k, n);
    // 需要干掉含min的gcd>1的
    // gcd从min的因子里面选
    VI fs = factors(min);
    for (auto x : fs) {
        if (x == 1) {
            continue;
        }
        int gcd_is_x = count(min / x, k / x);
        ans = sub(ans, gcd_is_x);
    }
    // log("count(min=%d,k=%d,n=%d)=%d\n", min, k, n, ans);
    if (k <= k_threshold) {
        count_small_cache[k][min] = ans;
    }
    return ans;
}

int count_cache[100001];
int count_cache_hit = 0;

// 1..k中可重复的选n个数使得gcd=1的方案数
int count(int k) {
    if (count_cache[k] >= 0) {
        count_cache_hit++;
        return count_cache[k];
    }
    int ans = 0;
    rep(min, 1, k + 1) {
        ans = add(ans, count(min, k));
    }
    log("count(k=%d,n=%d)=%d\n", k, n, ans);
    return count_cache[k] = ans;
}

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

    // VI fs = factors(100000);
    // sort(begin(fs), end(fs));
    // for (auto x : fs) {
    //     log("%d ", x);
    // }
    // log("\n");
    // log("solve1(%d,%d)=%d", 3, 200, solve1(200, 3));

    int k;
    cin >> n >> k;

    k_threshold = k / K_SHRINK;

    fill_n(count_cache, k + 1, -1);
    fill_n(power_cache, k + 1, -1);
    rep(i, 1, k_threshold + 1) {
        fill_n(count_small_cache[i], i + 1, -1);
    }

    int ans = 0;
    rep(gcd, 1, k + 1) {
        ans = add(ans, mul(gcd, count(k / gcd)));
    }

    log("\n");
    // log("k_div_min = %d\n", k_div_min);
    // log("max_q_sub_min=%d\n", max_q_sub_min);
    log("count_cache_hit=%d\n", count_cache_hit);
    // log("mins: ---------------");
    // for (auto x : mins) {
    //     log("%d ", x);
    // }
    // log("--------------\n");
    // log("ks: ---------------");
    // bool k1[k + 1];
    // for (auto x : ks) {
    //     // log("%d ", x);
    //     k1[x] = true;
    // }
    // int k1_cnt = 0;
    // rep(i, 0, k + 1) {
    //     if (k1[i]) {
    //         log("%d ", i);
    //         k1_cnt++;
    //     }
    // }
    // log("\n");
    // log("k1_cnt=%d\n", k1_cnt);
    // log("--------------\n");
    log("k_large=%d\n", k_large);
    log("k_small=%d\n", k_small);
    log("k_small_hit=%d\n", k_small_hit);
    log("factors_hit=%d\n", factors_hit);

    cout << ans;
}


Measured memory_bytes: 367984