#pragma GCC optimize("Ofast,O3,unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#define bp __builtin_popcountll
#define mp make_pair
#define pb push_back
#define vec vector
#define ll long long
#define F first
#define S second
#define pii pair <int, int>
#define elif else if
#define sz(a) int32_t(a.size())
#define lb lower_bound
#define ub upper_bound
#define all(a) a.begin(), a.end()
#define fl fflush(stdout)
#define ex exit(0)
#define int ll
using namespace std;
using namespace __gnu_pbds;
template <typename T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
mt19937 rnd(878787);
mt19937_64 gen(chrono::steady_clock::now().time_since_epoch().count());
const int N = 1e6 + 5;
const int mod = 1e9 + 7;
int n, m;
ll dp[N], sum[N];
main(){
ios_base::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n >> m;
dp[0] = 1;
for(int i = 1; i <= n; ++i){
for(int j = 0; j <= m; ++j){
if(j != 0) sum[j] = sum[j - 1];
sum[j] += dp[j];
sum[j] %= mod;
}
for(int j = m; j >= 0; --j){
int val = 0;
if(j - i >= 0) val = sum[j - i];
dp[j] = (sum[j] - val + mod) % mod;
}
for(int j = m; j >= 0; --j) sum[j] = 0;
}
cout << dp[m] % mod;
}
I3ByYWdtYSBHQ0Mgb3B0aW1pemUoIk9mYXN0LE8zLHVucm9sbC1sb29wcyIpCiNpbmNsdWRlIDxiaXRzL3N0ZGMrKy5oPgojaW5jbHVkZSA8ZXh0L3BiX2RzL2Fzc29jX2NvbnRhaW5lci5ocHA+CiNkZWZpbmUgYnAgX19idWlsdGluX3BvcGNvdW50bGwKI2RlZmluZSBtcCBtYWtlX3BhaXIKI2RlZmluZSBwYiBwdXNoX2JhY2sKI2RlZmluZSB2ZWMgdmVjdG9yCiNkZWZpbmUgbGwgbG9uZyBsb25nCiNkZWZpbmUgRiBmaXJzdAojZGVmaW5lIFMgc2Vjb25kCiNkZWZpbmUgcGlpIHBhaXIgPGludCwgaW50PgojZGVmaW5lIGVsaWYgZWxzZSBpZgojZGVmaW5lIHN6KGEpIGludDMyX3QoYS5zaXplKCkpCiNkZWZpbmUgbGIgbG93ZXJfYm91bmQKI2RlZmluZSB1YiB1cHBlcl9ib3VuZAojZGVmaW5lIGFsbChhKSBhLmJlZ2luKCksIGEuZW5kKCkKI2RlZmluZSBmbCBmZmx1c2goc3Rkb3V0KQojZGVmaW5lIGV4IGV4aXQoMCkKI2RlZmluZSBpbnQgbGwKdXNpbmcgbmFtZXNwYWNlIHN0ZDsKdXNpbmcgbmFtZXNwYWNlIF9fZ251X3BiZHM7CnRlbXBsYXRlIDx0eXBlbmFtZSBUPiB1c2luZyBvcmRlcmVkX3NldCA9IHRyZWU8VCwgbnVsbF90eXBlLCBsZXNzPFQ+LCByYl90cmVlX3RhZywgdHJlZV9vcmRlcl9zdGF0aXN0aWNzX25vZGVfdXBkYXRlPjsKbXQxOTkzNyBybmQoODc4Nzg3KTsKbXQxOTkzN182NCBnZW4oY2hyb25vOjpzdGVhZHlfY2xvY2s6Om5vdygpLnRpbWVfc2luY2VfZXBvY2goKS5jb3VudCgpKTsKY29uc3QgaW50IE4gPSAxZTYgKyA1Owpjb25zdCBpbnQgbW9kID0gMWU5ICsgNzsKaW50IG4sIG07CmxsIGRwW05dLCBzdW1bTl07CiAKbWFpbigpewogICAgaW9zX2Jhc2U6OnN5bmNfd2l0aF9zdGRpbygwKTsKICAgIGNpbi50aWUoMCk7IGNvdXQudGllKDApOwogCiAgICBjaW4gPj4gbiA+PiBtOwogCiAgICBkcFswXSA9IDE7CiAKICAgIGZvcihpbnQgaSA9IDE7IGkgPD0gbjsgKytpKXsKIAogICAgICAgIGZvcihpbnQgaiA9IDA7IGogPD0gbTsgKytqKXsKICAgICAgICAgICAgaWYoaiAhPSAwKSBzdW1bal0gPSBzdW1baiAtIDFdOwogICAgICAgICAgICBzdW1bal0gKz0gZHBbal07CiAgICAgICAgICAgIHN1bVtqXSAlPSBtb2Q7CiAgICAgICAgfQogCiAgICAgICAgZm9yKGludCBqID0gbTsgaiA+PSAwOyAtLWopewogICAgICAgICAgICBpbnQgdmFsID0gMDsKICAgICAgICAgICAgaWYoaiAtIGkgPj0gMCkgdmFsID0gc3VtW2ogLSBpXTsKICAgICAgICAgICAgZHBbal0gPSAoc3VtW2pdIC0gdmFsICsgbW9kKSAlIG1vZDsKICAgICAgICB9CiAgICAgICAgZm9yKGludCBqID0gbTsgaiA+PSAwOyAtLWopIHN1bVtqXSA9IDA7CiAKIAogICAgfQogCiAgICBjb3V0IDw8IGRwW21dICUgbW9kOwp9