#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math,O3")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
#define speed                   \
  ios_base::sync_with_stdio(0); \
  cin.tie(0);                   \
  cout.tie(0);
#define oprecision    \
  cout.precision(30); \
  cerr.precision(7);
#define ll long long
#define ld long double
#define ss string
#define pii pair<int, int>
#define pll pair<ll, ll>
#define forn(n) for (int i = 1; i <= n; i++)
#define forlr(l, r) \
  for (int i = l; (l > r ? i >= r : i <= r); (l > r ? i-- : i++))
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
#define pb(x) push_back(x)
#define pc(x) __builtin_popcount(x)
#define pcll(x) __builtin_popcountll(x)
#define mp(x, y) make_pair(x, y)
#define F first
#define S second
using namespace std;
using namespace std;
const int mod = 1000000007;
int n, m, dp[20][1005][1005][5];
inline void add(int &a, int b) {
  a += b;
  if (a >= mod) a -= mod;
}
int rec(int v = 1, int a = 1, int b = n, int c = 1) {
  if (a > n || 1 > b || a > b) return 0;
  if (v > m) return 1;
  int &x = dp[v][a][b][c];
  if (~x) return x;
  add(x, 1);
  if (c) add(x, rec(v, a + 1, b, 1));
  add(x, rec(v, a, b - 1, 0));
  add(x, rec(v + 1, a, b, 1));
  return x;
}
int main() {
  speed;
  oprecision;
  // code
  memset(dp, -1, sizeof dp);
  cin >> n >> m;
  cout << rec();
  // endl
#ifndef ONLINE_JUDGE
  cerr << "\nTime elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
  return 0;
}


#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math,O3")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
#define speed                                                                  \
  ios_base::sync_with_stdio(0);                                                \
  cin.tie(0);                                                                  \
  cout.tie(0);
#define oprecision                                                             \
  cout.precision(6);                                                           \
  cerr.precision(7);
#define bb bool
#define ii int
#define ll long long
#define ff float
#define dd double
#define cc char
#define ss string
#define forn(sz) for (int i = 1; i <= sz; i++)
#define forni(i, sz) for (int i = 1; i <= sz; i++)
#define fornid(i, m, sz) for (int i = m; i <= sz; i++)
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define vii vector<ii>
#define vii64 vector<ll>
#define vb vector<bb>
using namespace std;
const int MOD = 1000000007;
int n, m, dp[12][1005][1005][3];
inline void add(int &a, int b) {
  a += b;
  if (a >= MOD)
    a -= MOD;
}
int rec(int v, int pa, int pb, bool c) {
  if (pa > n || pb < 1 || pa > pb)
    return 0;
  if (v > m)
    return 1;
  if (dp[v][pa][pb][c] != -1)
    return dp[v][pa][pb][c];
  int cur = 0;
  if (c)
    add(cur, rec(v, pa + 1, pb, 1));
  add(cur, rec(v, pa, pb - 1, 0));
  add(cur, rec(v + 1, pa, pb, 1));
  add(cur, 0);
  return dp[v][pa][pb][c] = cur;
}
int main() {
  speed;
  oprecision;
  // code
  memset(dp, -1, sizeof dp);
  cin >> n >> m;
  cout << rec(1, 1, n, 1);
  // endl
#ifndef ONLINE_JUDGE
  cerr << "\nTime elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
  return 0;
}


#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math,O3")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
#define speed                                                                  \
  ios_base::sync_with_stdio(0);                                                \
  cin.tie(0);                                                                  \
  cout.tie(0);
#define oprecision                                                             \
  cout.precision(6);                                                           \
  cerr.precision(7);
#define bb bool
#define ii int
#define ll long long
#define ff float
#define dd double
#define cc char
#define ss string
#define forn(sz) for (int i = 1; i <= sz; i++)
#define forni(i, sz) for (int i = 1; i <= sz; i++)
#define fornid(i, m, sz) for (int i = m; i <= sz; i++)
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define vii vector<ii>
#define vii64 vector<ll>
#define vb vector<bb>
using namespace std;
const int MOD = 1000000007;
int n, m, dp[22][1005][1005][4];
inline void add(int &a, int b) {
  a += b;
  if (a >= MOD)
    a -= MOD;
}
int rec(int v, int pa, int pb, bool c) {
  if (pa > n || pb < 1 || pa > pb)
    return 0;
  if (v > m)
    return 1;
  if (dp[v][pa][pb][c] != -1)
    return dp[v][pa][pb][c];
  int cur = 0;
  if (c)
    add(cur, rec(v, pa + 1, pb, 1));
  add(cur, rec(v, pa, pb - 1, 0));
  add(cur, rec(v + 1, pa, pb, 1));
  add(cur, 0);
  return dp[v][pa][pb][c] = cur;
}
int main() {
  speed;
  oprecision;
  // code
  memset(dp, -1, sizeof dp);
  cin >> n >> m;
  cout << rec(1, 1, n, 1);
  // endl
#ifndef ONLINE_JUDGE
  cerr << "\nTime elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
  return 0;
}


#include <stdio.h>
int mod = 1000000007;
unsigned long long pow (unsigned long long x, int p = mod - 2) {
    unsigned long long res = 1;
    while (p) {
        if (p & 1) res = (res * x) % mod;
        p >>= 1;
        x = (x * x) % mod;
    }
    return res;
}
int main() {
    short int n, m;
    scanf("%hi%hi", &n, &m);
    //! _2 * m   2 * m
    //! C     = C
    //!  n       n + 2 * m - 1
    unsigned long long res = 1, denom = 1;
    for (int i = n; i < n + 2 * m; i++)
        res = (res * i) % mod;
    for (int i = 2; i <= 2 * m; i++)
        denom = (denom * i) % mod;
    printf("%llu", (res * pow(denom)) % mod);
}


#include <stdio.h>
unsigned long long memC[1020][21];
unsigned long long C(short int n, short int p) {
    if (n == p || p == 0) return 1;
    if (!memC[n][p])
        memC[n][p] = (C(n - 1, p) % 1000000007 + C(n - 1, p - 1) % 1000000007) % 1000000007;
    return memC[n][p];
}
int main() {
    short int n, m;
    scanf("%hi%hi", &n, &m);
    //! _2 * m   2 * m
    //! C     = C
    //!  n       n + 2 * m - 1
    printf("%llu", C(n + (m << 1) - 1, (m << 1)));
}


#include <stdio.h>
int main() {
    unsigned long long n;
    short int m;
    scanf("%llu%hi", &n, &m);
    unsigned long long A[1001];
    A[0] = 0;
    for (int i = 1; i <= n; i++) A[i] = 1;

    for (int lvl = 0; lvl < 2 * m; lvl++) {
        for (short int i = 1; i <= n; i++) {
            A[i] += A[i - 1];
            A[i] %= 1000000007;
        }
    }
    printf("%llu", A[n]);
}


#include <stdio.h>
unsigned long long memC[1001][1001];
unsigned long long C(short int n, short int p) {
    if (n == p || p == 0) return 1;
    if (!memC[n][p])
        memC[n][p] = (C(n - 1, p) % 1000000007 + C(n - 1, p - 1) % 1000000007) % 1000000007;
    return memC[n][p];
}
int main() {
    short int n, m;
    scanf("%hi%hi", &n, &m);
    //! _2 * m   2 * m
    //! C     = C
    //!  n       n + 2 * m - 1
    printf("%llu", C(n + (m << 1) - 1, (m << 1)));
}


#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
long long n,m;
long long dp[25][1010];

long long recur(int id, int num){
    if(num == n) return 1;
    if(id >= m)return 1;
    if(dp[id][num] != -1) return dp[id][num];
    return dp[id][num] = (recur(id+1,num) + recur(id,num+1)) % mod;
}

int main(){
    cin>>n>>m;
    memset(dp, -1, sizeof dp);
    m *= 2;
    cout<<recur(0,1) % mod;
}


#include <bits/stdc++.h>
using namespace std;
int n,m;
int dp[25][1010];

int recur(int id, int num){
    if(num == n) return 1;
    if(id >= m)return 1;
    if(dp[id][num] != -1) return dp[id][num];
    return dp[id][num] = recur(id+1,num) + recur(id,num+1);
}

int main(){
    cin>>n>>m;
    memset(dp, -1, sizeof dp);
    m *= 2;
    cout<<recur(0,1);
}


#include <bits/stdc++.h>
using namespace std;
int n,m;
int dp[2010][15];

int recur(int id, int num){
    if(num == n) return 1;
    if(id >= m)return 1;
    if(dp[id][num] != -1) return dp[id][num];
    return dp[id][num] = recur(id+1,num) + recur(id,num+1);
}

int main(){
    cin>>n>>m;
    memset(dp, -1, sizeof dp);
    m *= 2;
    cout<<recur(0,1);
}


#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int n,m;
int dp[25][1010];

int recur(int id, int num){
    if(dp[id][num] != -1) return dp[id][num];
    if(id == m) return 1;
    if(num == n) return 1;
    return dp[id][num] = (recur(id+1,num) + recur(id,num+1)) % mod;
}

int main(){
    cin>>n>>m;
    memset(dp, -1, sizeof dp);
    m *= 2;
    cout<<recur(0,1);
}


#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
long long n,m;
long long dp[2010][15];

long long recur(int id, int num){
    if(num == n) return 1;
    if(id >= m)return 1;
    if(dp[id][num] != -1) return dp[id][num];
    return dp[id][num] = (recur(id+1,num) + recur(id,num+1)) % mod;
}

int main(){
    cin>>n>>m;
    memset(dp, -1, sizeof dp);
    m *= 2;
    cout<<recur(0,1) % mod;
}


#include<bits/stdc++.h>

using namespace std;

#define ll long long int

ll power(ll x, ll y, ll p)
{
	ll res = 1; x = x%p;
	while(y<0)
	{
		if(y&1)
		res = (res*x)%p;

		y = y>>1;
		x = (x*x)%p;
	}
	return res;
}

ll inm(ll x, ll p)
{
	return (power(x,p-2,p));
}

int main ()
{
	int n,m;
	ll a=1,b,c,p=1000000007;
	cin>>n>>m;
	for(int i=1;i<=(n+2*m-1);i++)
	{
		a = (a*i)%p;
		if(i=2*m) b = a;
		if(i=(n-1)) c = a;
	}
	cout<<(a * inm(b,p) % p  * inm(c,p) % p);
	return 0;
}


#include<bits/stdc++.h>

using namespace std;

int main ()
{
	int n,m;
	long long int pro=1,rro=1;
	cin>>n>>m;
	for(int i=0;i<2*m;i++)
	{
		pro = pro * (n+(2*m)-1-i);
	}
	for(int i=1;i<=2*m;i++)
	rro = rro * (i);

	cout<<(pro/rro);
	return 0;
}


#include<bits/stdc++.h>

using namespace std;

#define ll long long int

ll power(ll x, ll y, ll p)
{
	ll res = 1; x = x%p;
	while(y>0)
	{
		if(y&1)
		res = (res*x)%p;

		y = y>>1;
		x = (x*x)%p;
	}
	return res;
}

ll inm(ll x, ll p)
{
	return (power(x,p-2,p));
}

int main ()
{
	int n,m;
	ll a=1,b,c,p=1000000007;
	cin>>n>>m;
	for(int i=1;i<=(n+2*m-1);i++)
	{
		a = (a*i)%p;
		if(i==2*m) b = a;
		if(i==(n-1)) c = a;
	}
	cout<<((a * (inm(b,p) % p ) * (inm(c,p) % p))%p);
	return 0;
}


#include<bits/stdc++.h>

using namespace std;

#define ll long long int

ll power(ll x, ll y, ll p)
{
	ll res = 1; x = x%p;
	while(y>0)
	{
		if(y&1)
		res = (res*x)%p;

		y = y>>1;
		x = (x*x)%p;
	}
	return res;
}

ll inm(ll x, ll p)
{
	return (power(x,p-2,p));
}

int main ()
{
	int n,m;
	ll a=1,b=1,c=1,p=1000000007;
	cin>>n>>m;
	for(int i=1;i<=(n+2*m-1);i++)
	{
		a = (a*i)%p;
		if(i==2*m) b = a;
		if(i==(n-1)) c = a;
	}
	cout<<(((a * (inm(b,p) % p ))%p * (inm(c,p) % p))%p);
	return 0;
}


#include<bits/stdc++.h>

using namespace std;

#define ll long long int

ll power(ll x, ll y, ll p)
{
	ll res = 1; x = x%p;
	while(y>0)
	{
		if(y&1)
		res = (res*x)%p;

		y = y>>1;
		x = (x*x)%p;
	}
	return res;
}

ll inm(ll x, ll p)
{
	return (power(x,p-2,p));
}

int main ()
{
	int n,m;
	ll a=1,b,c,p=1000000007;
	cin>>n>>m;
	for(int i=1;i<=(n+2*m-1);i++)
	{
		a = (a*i)%p;
		if(i==2*m) b = a;
		if(i==(n-1)) c = a;
	}
	cout<<(((a * (inm(b,p) % p ))%p * (inm(c,p) % p))%p);
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int MAXINT = 1073741823;

const long long int M = 1000000007;

const int MAXN = 1030;

const long long int MOD = 1000000007;

long long int dp[MOD][MOD];

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	long long int a, b, answer;
	cin >> a >> b;
	for (int i = 0; i < MOD; i++) {
		dp[i][0] = 1;
		dp[i][i] = 1;
		for (int k = 1; k < i; k++)
			dp[i][k] = (dp[i - 1][k] + dp[i - 1][k - 1]) % MOD;
	}
	answer = 2 * b - 1 + a;
	cout << dp[answer][a - 1] % MOD;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int MAXINT = 1073741823;

const long long int M = 1000000007;

const int MAXN = 1005;

const long long int MOD = 1000000007;

long long int dp[MAXN][MAXN];

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	long long int a, b, answer;
	cin >> a >> b;
	for (int i = 0; i < MAXN; i++) {
		dp[i][0] = 1;
		dp[i][i] = 1;
		for (int k = 1; k < i; k++) {
			dp[i][k] = (dp[i - 1][k] + dp[i - 1][k - 1]);
			dp[i][k] %= MOD;
		}
	}
	answer = 2 * b - 1 + a;
	cout << dp[answer][a - 1] % MOD;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int MAXINT = 1073741823;

const long long int M = 1000000007;

const int MAXN = 1030;

const long long int MOD = 1000000007;

long long int dp[MAXN][MAXN];

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	long long int a, b, answer;
	cin >> a >> b;
	for (int i = 0; i < MAXN; i++) {
		dp[i][0] = 1;
		dp[i][i] = 1;
		for (int k = 1; k < i; k++) {
			dp[i][k] = (dp[i - 1][k] + dp[i - 1][k - 1]);
			dp[i][k] %= MOD;
		}
	}
	answer = 2 * b - 1 + a;
	cout << dp[answer][a - 1] % MOD;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const long long MAXN = 1030, MOD = 1000000007;

long long dp[MAXN][MAXN];

int main() {
    long long a, b;
    cin >> a >> b;
    for (int i = 0; i < MAXN; i++) {
        dp[i][0] = 1;
        dp[i][i] = 1;
        for (int k = 1; k < i; k++)
            dp[i][k] = (dp[i - 1][k] + dp[i - 1][k - 1]) % MOD;
    }
    long long answer = 2 * b + a - 1;
    cout << dp[answer][a - 1] % MOD << endl;

}


#include <bits/stdc++.h>

using namespace std;

const int MAXINT = 1073741823;

const long long int M = 1000000007;

const int MOD = 1030;

long long int dp[MOD][MOD];

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	long long int a, b, answer;
	cin >> a >> b;
	for (int i = 0; i < MOD; i++) {
		dp[i][0] = 1;
		dp[i][i] = 1;
		for (int k = 1; k < i; k++)
			dp[i][k] = (dp[i - 1][k] + dp[i - 1][k - 1]) % MOD;
	}
	answer = 2 * b - 1 + a;
	cout << dp[answer][a - 1] % MOD;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define f first
#define s second
#define pb push_back
#define mp make_pair
#define all(v) v.begin(), v.end()
#define sz(v) (int)v.size()

#define Fl(i, a, b) for(int i=a; i<b; i++)
#define Fle(i, a, b) for(int i=a; i<=b; i++)
#define Flz(i, a) for(int i=0; i<a; i++)
#define Fld(i,a,b) for(int i = (b)-1; i >= a; i--)
#define Fldz(i,a) for(int i = (a)-1; i>=0; i--)

#define FAST ios::sync_with_stdio(0); cin.tie(0);
#define finish(x) return cout << x << '\n', 0;
#define dbg(x) cerr << ">>> " << #x << " = " << x << "\n";
#define _ << " _ " <<

#define llfill(v, n)  while(n--){ll x; cin >> x; v.push_back(x);}

typedef long long ll;
typedef long double ld;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef pair<int,int> pi;
typedef pair<ld,ld> pd;
typedef complex<ld> cd;

const int mod = int(1e9) + 7;

int fact(int x){
    if (x == 1) return 1;
    else return x * fact(x-1);
}

int main(){ FAST
    int n, m; cin >> n >> m;
    if(n == 1) cout << "1\n";
    else cout <<  (fact(n + 2*m - 1)/ (fact(2*m) * fact(n-1))) % mod << "\n";;
}

// Compile: g++ -std=c++11 -O2 -Wall test.cpp -o test
// Run: ./test


#include <bits/stdc++.h>
using namespace std;

#define f first
#define s second
#define pb push_back
#define mp make_pair
#define all(v) v.begin(), v.end()
#define sz(v) (int)v.size()

#define Fl(i, a, b) for(int i=a; i<b; i++)
#define Fle(i, a, b) for(int i=a; i<=b; i++)
#define Flz(i, a) for(int i=0; i<a; i++)
#define Fld(i,a,b) for(int i = (b)-1; i >= a; i--)
#define Fldz(i,a) for(int i = (a)-1; i>=0; i--)

#define FAST ios::sync_with_stdio(0); cin.tie(0);
#define finish(x) return cout << x << '\n', 0;
#define dbg(x) cerr << ">>> " << #x << " = " << x << "\n";
#define _ << " _ " <<

#define llfill(v, n)  while(n--){ll x; cin >> x; v.push_back(x);}

typedef long long ll;
typedef long double ld;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef pair<int,int> pi;
typedef pair<ld,ld> pd;
typedef complex<ld> cd;

const int mod = int(1e9) + 7;

ll fact(ll x){
    if (x == 1) return 1;
    else return x * fact(x-1);
}

int main(){ FAST
    ll n, m; cin >> n >> m;
    if(n == 1) cout << "1\n";
    else cout <<  (fact(n + 2*m - 1)/ (fact(2*m) * fact(n-1))) % mod << "\n";;
}

// Compile: g++ -std=c++11 -O2 -Wall test.cpp -o test
// Run: ./test


#include <bits/stdc++.h>
using namespace std;

#define f first
#define s second
#define pb push_back
#define mp make_pair
#define all(v) v.begin(), v.end()
#define sz(v) (int)v.size()

#define Fl(i, a, b) for(int i=a; i<b; i++)
#define Fle(i, a, b) for(int i=a; i<=b; i++)
#define Flz(i, a) for(int i=0; i<a; i++)
#define Fld(i,a,b) for(int i = (b)-1; i >= a; i--)
#define Fldz(i,a) for(int i = (a)-1; i>=0; i--)

#define FAST ios::sync_with_stdio(0); cin.tie(0);
#define finish(x) return cout << x << '\n', 0;
#define dbg(x) cerr << ">>> " << #x << " = " << x << "\n";
#define _ << " _ " <<

#define llfill(v, n)  while(n--){ll x; cin >> x; v.push_back(x);}

typedef long long ll;
typedef long double ld;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef pair<int,int> pi;
typedef pair<ld,ld> pd;
typedef complex<ld> cd;

const int mod = int(1e9) + 7;

int fact(int x){
    if (x == 1) return 1;
    else return x * fact(x-1);
}

int main(){ FAST
    int n, m; cin >> n >> m;
    cout <<  (fact(n + 2*m - 1)/ (fact(2*m) * fact(n-1))) % mod << "\n";;
}

// Compile: g++ -std=c++11 -O2 -Wall test.cpp -o test
// Run: ./test


#include <bits/stdc++.h>
using namespace std;

#define f first
#define s second
#define pb push_back
#define mp make_pair
#define all(v) v.begin(), v.end()
#define sz(v) (int)v.size()

#define Fl(i, a, b) for(int i=a; i<b; i++)
#define Fle(i, a, b) for(int i=a; i<=b; i++)
#define Flz(i, a) for(int i=0; i<a; i++)
#define Fld(i,a,b) for(int i = (b)-1; i >= a; i--)
#define Fldz(i,a) for(int i = (a)-1; i>=0; i--)

#define FAST ios::sync_with_stdio(0); cin.tie(0);
#define finish(x) return cout << x << '\n', 0;
#define dbg(x) cerr << ">>> " << #x << " = " << x << "\n";
#define _ << " _ " <<

#define llfill(v, n)  while(n--){ll x; cin >> x; v.push_back(x);}

typedef long long ll;
typedef long double ld;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef pair<int,int> pi;
typedef pair<ld,ld> pd;
typedef complex<ld> cd;

const ll mod = int(1e9) + 7;

ll inv(ll x){
    ll curr = x; ll res = 1; ll pow = mod-2;
    while(pow != 0){
        ll rem = pow % 2; pow /= 2;
        if(rem == 1) res = (res * curr) % mod;
        curr = (curr * curr) % mod;
    }
    return res;
}

int main(){ FAST
    ll n, m; cin >> n >> m;
    ll fact[n + 2*m];
    fact[0] = 1;
    for(ll i = 1; i < n+2*m; i++){
        fact[i] = fact[i-1] * i % mod;
    }
    cout << (fact[n+ 2*m - 1] * inv(fact[2*m]) % mod) * inv(fact[n-1]) % mod << "\n";
}

// Compile: g++ -std=c++11 -O2 -Wall test.cpp -o test
// Run: ./test


#pragma GCC target ("avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")
#include<bits/stdc++.h>
#define fast_az_fuk ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define ll long long
#define int ll
#define ull unsigned ll
#define ld long double
#define pb push_back
#define pf push_front
#define dll deque<ll>
#define vll vector<ll>
#define pll pair<ll,ll>
#define vpll vector<pll>
#define dpll deque<pll>
#define mapll map<ll,ll>
#define endl "\n"
#define all(v) v.begin(),v.end()
#define ms(a,x) memset(a,x,sizeof(a))
using namespace std;
const ll p=1e9+7;
const ll N=1e3;
ll fact[N+1];
ull power(ll x,ull y)
{
    if(x==0) return 0;
    ull res=1;
    while(y)
    {
        if(y&1) res=(res*x)%p;
        x=(x*x)%p; y>>=1;
    }
    return res;
}
ll nCr(ll n,ll r){
    if(n<0) return 0;
    if(r>n||r<0) return 0;
    ll ans=fact[n];
    ans=(ans*power(fact[r],p-2))%p;
    ans=(ans*power(fact[n-r],p-2))%p;
    return ans;
}
int32_t main()
{
    #ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    #endif
    fast_az_fuk
    fact[0]=1;
    for(ll i=1;i<=N;i++){
        fact[i]=(fact[i-1]*i)%p;
    }
    ll n,m; cin>>n>>m;
    ll ways=0;
    for(ll i=1;i<=n;i++){
        ll temp=1;
        temp=(temp*nCr(m+i-2,i-1))%p;
        // cout<<i<<" "<<temp<<endl;
        temp=(temp*nCr(m+n-i,n-i))%p;
        // cout<<i<<" "<<temp<<endl;
        ways=(ways+temp)%p;
    }
    cout<<ways<<endl;
    return 0;
}


#pragma GCC target ("avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")
#include<bits/stdc++.h>
#define fast_az_fuk ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define ll long long
#define int ll
#define ull unsigned ll
#define ld long double
#define pb push_back
#define pf push_front
#define dll deque<ll>
#define vll vector<ll>
#define pll pair<ll,ll>
#define vpll vector<pll>
#define dpll deque<pll>
#define mapll map<ll,ll>
#define endl "\n"
#define all(v) v.begin(),v.end()
#define ms(a,x) memset(a,x,sizeof(a))
using namespace std;
const ll p=1e9+7;
const ll N=1010;
ll fact[N+1];
ull power(ll x,ull y)
{
    if(x==0) return 0;
    ull res=1;
    while(y)
    {
        if(y&1) res=(res*x)%p;
        x=(x*x)%p; y>>=1;
    }
    return res;
}
ll nCr(ll n,ll r){
    if(n<0) return 0;
    if(r>n||r<0) return 0;
    ll ans=fact[n];
    ans=(ans*power(fact[r],p-2))%p;
    ans=(ans*power(fact[n-r],p-2))%p;
    return ans;
}
int32_t main()
{
    #ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    #endif
    fast_az_fuk
    fact[0]=1;
    for(ll i=1;i<=N;i++){
        fact[i]=(fact[i-1]*i)%p;
    }
    ll n,m; cin>>n>>m;
    ll ways=0;
    for(ll i=1;i<=n;i++){
        ll temp=1;
        temp=(temp*nCr(m+i-2,i-1))%p;
        // cout<<i<<" "<<temp<<endl;
        temp=(temp*nCr(m+n-i,n-i))%p;
        // cout<<i<<" "<<temp<<endl;
        ways=(ways+temp)%p;
    }
    cout<<ways<<endl;
    return 0;
}


#pragma GCC target ("avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")
#include<bits/stdc++.h>
#define fast_az_fuk ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define ll long long
#define int ll
#define ull unsigned ll
#define ld long double
#define pb push_back
#define pf push_front
#define dll deque<ll>
#define vll vector<ll>
#define pll pair<ll,ll>
#define vpll vector<pll>
#define dpll deque<pll>
#define mapll map<ll,ll>
#define endl "\n"
#define all(v) v.begin(),v.end()
#define ms(a,x) memset(a,x,sizeof(a))
using namespace std;
const ll p=1e9+7;
const ll N=1e3;
ll fact[N+1];
ull power(ll x,ull y)
{
    if(x==0) return 0;
    ull res=1;
    while(y)
    {
        if(y&1) res=(res*x)%p;
        x=(x*x)%p; y>>=1;
    }
    return res;
}
ll nCr(ll n,ll r){
    if(n<0) return 0;
    if(r>n||r<0) return 0;
    ll ans=fact[n];
    ans=(ans*power(fact[r],p-2))%p;
    ans=(ans*power(fact[n-r],p-2))%p;
}
int32_t main()
{
    #ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    #endif
    fast_az_fuk
    fact[0]=1;
    for(ll i=1;i<=N;i++){
        fact[i]=(fact[i-1]*i)%p;
    }
    ll n,m; cin>>n>>m;
    ll ways=0;
    for(ll i=1;i<=n;i++){
        ll temp=1;
        temp=(temp*nCr(m+i-2,i-1))%p;
        // cout<<i<<" "<<temp<<endl;
        temp=(temp*nCr(m+n-i,n-i))%p;
        // cout<<i<<" "<<temp<<endl;
        ways=(ways+temp)%p;
    }
    cout<<ways<<endl;
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define forn(i,n) for(ll i=0;i<n;i++)
#define forn1(i,a,n) for(ll i=a;i<=n;i++)
#define FIO ios_base::sync_with_stdio(false); cin.tie(NULL);
#define tc ll t;cin>>t; for(ll i=0;i<t;i++)
ll power(ll a,ll b,ll c){ ll ans=1;
    while(b>0){  if(b&1){ ans=ans*a; ans%=c;    }
        a=a*a;  a%=c; b=b>>1; }
    return ans;  }

int main(){
    ll n,m;
   cin>>n>>m;
    ll temp[1005];
    ll mod=pow(10,9)+7;
    temp[0]=1;
    forn1(i,1,1000){
        temp[i]=(i*temp[i-1])%mod;
    }
   ll k=2*m;
   ll ans1=power(temp[n-1],mod-2,mod);
   ll ans2=power(temp[k],mod-2,mod);
   ll ans=(((temp[n+k-1]*ans1)%mod)*ans2)%mod;
   cout<<ans<<endl;

}


#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define forn(i,n) for(ll i=0;i<n;i++)
#define forn1(i,a,n) for(ll i=a;i<=n;i++)
#define FIO ios_base::sync_with_stdio(false); cin.tie(NULL);
#define tc ll t;cin>>t; for(ll i=0;i<t;i++)
ll power(ll a,ll b,ll c){ ll ans=1;
    while(b>0){  if(b&1){ ans=ans*a; ans%=c;    }
        a=a*a;  a%=c; b=b>>1; }
    return ans;  }

int main(){
    ll n,m;
   cin>>n>>m;
    ll dp[3*m][n+1];
    ll mod=pow(10,9)+7;
    memset(dp,0,sizeof(dp));
    ll c=power(2,mod-2,mod);
    for(ll i=1;i<=2*m;i++){
        for(ll j=0;j<=n;j++){
            if(j==0){
                dp[i][j]=0;
                continue;
            }else if(i==1){
                dp[i][j]=j;
            }else{
               dp[i][j]=j;
               for(ll k=1;k<i;k++){
                   ll a=(j*dp[i-k][j-1])%mod;
                   ll b=(a*c)%mod;
                  dp[i][j]=dp[i][j]+b;
                  dp[i][j]%=mod;
               }
            }
        }
    }
    cout<<dp[2*m][n]<<endl;
}


#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define forn(i,n) for(ll i=0;i<n;i++)
#define forn1(i,a,n) for(ll i=a;i<=n;i++)
#define FIO ios_base::sync_with_stdio(false); cin.tie(NULL);
#define tc ll t;cin>>t; for(ll i=0;i<t;i++)
ll power(ll a,ll b,ll c){ ll ans=1;
    while(b>0){  if(b&1){ ans=ans*a; ans%=c;    }
        a=a*a;  a%=c; b=b>>1; }
    return ans;  }

int main(){
    ll n,m;
   cin>>n>>m;
    ll temp[1050];
    memset(temp,0,sizeof(temp));
    ll mod=pow(10,9)+7;
    temp[0]=1;
    forn1(i,1,1040){
        temp[i]=(i*temp[i-1])%mod;
    }
   ll k=2*m;
   ll ans1=power(temp[n-1],mod-2,mod);
   ll ans2=power(temp[k],mod-2,mod);
   ll ans=(((temp[n+k-1]*ans1)%mod)*ans2)%mod;
   cout<<ans<<endl;

}


#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define forn(i,n) for(ll i=0;i<n;i++)
#define forn1(i,a,n) for(ll i=a;i<=n;i++)
#define FIO ios_base::sync_with_stdio(false); cin.tie(NULL);
#define tc ll t;cin>>t; for(ll i=0;i<t;i++)
ll power(ll a,ll b,ll c){ ll ans=1;
    while(b>0){  if(b&1){ ans=ans*a; ans%=c;    }
        a=a*a;  a%=c; b=b>>1; }
    return ans;  }

int main(){
    ll n,m;
   cin>>n>>m;
    ll temp[1050];
    ll mod=pow(10,9)+7;
    temp[0]=1;
    forn1(i,1,1000){
        temp[i]=(i*temp[i-1])%mod;
    }
   ll k=2*m;
   ll ans1=power(temp[n-1],mod-2,mod);
   ll ans2=power(temp[k],mod-2,mod);
   ll ans=(((temp[n+k-1]*ans1)%mod)*ans2)%mod;
   cout<<ans<<endl;

}


#include <bits/stdc++.h>
#define inchar			getchar
#define outchar(x)		putchar(x)
#define ll long long
#define int long long //
#define all(v) v.begin(), v.end()
#define SP outchar(' ')
#define trace(x) cerr<<#x<<": "<<x<<" "<<endl;
#define LN outchar('\n')
#define endl '\n'
using namespace std;

template<typename T> void inpos(T &x){x=0;register T c=inchar();while(((c<48)||(c>57))&&(c!='-'))c=inchar();bool neg=0; if(c=='-')neg=1;for(;c<48||c>57;c=inchar());for(;c>47&&c<58;c=inchar())x=(x<<3)+(x<<1)+(c&15);if(neg)x=-x;}
template<typename T> void outpos(T n){if(n<0){outchar('-');n*=-1;}char snum[65];int i=0;do{snum[i++]=n%10+'0';n/=10;}while(n);i=i-1;while(i>=0)outchar(snum[i--]);}
inline void instr(char *str){register char c=0;register int i=0;while(c<33)c=inchar();while(c!='\n'&&c!=' '&&c!=EOF){str[i]=c;c=inchar();++i;}str[i]='\0';}

const int mod = 1e9 + 7;

int dp[1005][25];

int32_t main () {
	int n ; int m;
	inpos(n); inpos(m);

	// number of non decreasing seq of length 2 * m
	//number of ways to reach by only taking down and right
	dp[0][0] = 1;
	m =m<<1;
	for (int i = 0; i<n;i++) {
		for (int j = 0; j<m;j++) {
			if (i==0 && j == 0) {
				dp[i][j] = 1;

				continue;}
			int A = (i-1>=0)?dp[i-1][j]:0;
			int B = (j-1>=0)?dp[i][j-1]:0;
			dp[i][j] = (A +B)%mod;
			dp[i][j]%=mod;

		}

	}

	int ans = 0;
	for (int i = 0; i<n;i++) {
		ans += 	dp[i][m-1];
	}

	outpos(ans%mod);LN;
}


#include <bits/stdc++.h>
#define inchar			getchar
#define outchar(x)		putchar(x)
#define ll long long
#define int long long //
#define all(v) v.begin(), v.end()
#define SP outchar(' ')
#define trace(x) cerr<<#x<<": "<<x<<" "<<endl;
#define LN outchar('\n')
#define endl '\n'
using namespace std;

template<typename T> void inpos(T &x){x=0;register T c=inchar();while(((c<48)||(c>57))&&(c!='-'))c=inchar();bool neg=0; if(c=='-')neg=1;for(;c<48||c>57;c=inchar());for(;c>47&&c<58;c=inchar())x=(x<<3)+(x<<1)+(c&15);if(neg)x=-x;}
template<typename T> void outpos(T n){if(n<0){outchar('-');n*=-1;}char snum[65];int i=0;do{snum[i++]=n%10+'0';n/=10;}while(n);i=i-1;while(i>=0)outchar(snum[i--]);}
inline void instr(char *str){register char c=0;register int i=0;while(c<33)c=inchar();while(c!='\n'&&c!=' '&&c!=EOF){str[i]=c;c=inchar();++i;}str[i]='\0';}

const int mod = 1e9 + 7;

int dp[1005][25];

int32_t main () {
	int n ; int m;
	inpos(n); inpos(m);

	//number of ways to reach by only taking down and right
	dp[0][0] = 1;
	m =m<<1;
	for (int i = 0; i<n;i++) {
		for (int j = 0; j<m;j++) {
			if (i==0 && j == 0) {
				dp[i][j] = 1;
				// cout << 1 << " ";
				continue;}
			int A = (i-1>=0)?dp[i-1][j]:0;
			int B = (j-1>=0)?dp[i][j-1]:0;
			dp[i][j] = (A +B)%mod;
			dp[i][j]%=mod;
			// cout << dp[i][j] << " ";
		}
		// cout << endl;
	}
//	vector<int> vec;
	int ans = 0;
	for (int i = 0; i<n;i++) {
		// vec.push_back(dp[i][m-1]);
		ans += 	dp[i][m-1];
	}

	// reverse(all(vec));
	// for(int i = 0; i<n;i++) {
	// 	for (int j = 0 ; j<=i;j++) {ans += vec[i]*vec[j];ans%=mod;}
	// }

	// for_each(all(vec), [](auto i){cout<< i << " ";});
	// mth digt
	// for (int i = 0 ; i< n; i ++) {
	// 	// trace(dp[i][m-1]); trace(n-i);
	// 	ans  = ans +( vec[i]*(n-i))%mod ;
	// 	ans%=mod;
	// }

	// for (int i = 0; i<n;i++) {
	// 	for(int j =1; j<m;j++) {
	// 		ans+= dp[i][j] * dp[][];ans%=mod;
	// 	}
	// }

	outpos(ans%mod);LN;

}


#include <bits/stdc++.h>
#define inchar			getchar
#define outchar(x)		putchar(x)
#define ll long long
#define int long long //
#define all(v) v.begin(), v.end()
#define SP outchar(' ')
#define trace(x) cerr<<#x<<": "<<x<<" "<<endl;
#define LN outchar('\n')
#define endl '\n'
using namespace std;

template<typename T> void inpos(T &x){x=0;register T c=inchar();while(((c<48)||(c>57))&&(c!='-'))c=inchar();bool neg=0; if(c=='-')neg=1;for(;c<48||c>57;c=inchar());for(;c>47&&c<58;c=inchar())x=(x<<3)+(x<<1)+(c&15);if(neg)x=-x;}
template<typename T> void outpos(T n){if(n<0){outchar('-');n*=-1;}char snum[65];int i=0;do{snum[i++]=n%10+'0';n/=10;}while(n);i=i-1;while(i>=0)outchar(snum[i--]);}
inline void instr(char *str){register char c=0;register int i=0;while(c<33)c=inchar();while(c!='\n'&&c!=' '&&c!=EOF){str[i]=c;c=inchar();++i;}str[i]='\0';}

const int mod = 1e9 + 7;

int dp[1005][15];

int32_t main () {
	int n ; int m;
	inpos(n); inpos(m);

	//number of ways to reach by only taking down and right
	dp[0][0] = 1;

	for (int i = 0; i<n;i++) {
		for (int j = 0; j<m;j++) {
			if (i==0 && j == 0) {dp[i][j] = 1;cout << 1 << " ";continue;}
			int A = (i-1>=0)?dp[i-1][j]:0;
			int B = (j-1>=0)?dp[i][j-1]:0;
			dp[i][j] = (A +B)%mod;
			cout << dp[i][j] << " ";
		}
		cout << endl;
	}
	vector<int> vec;
	for (int i = 0; i<n;i++) {
		vec.push_back(dp[i][m-1]);
	}
	reverse(all(vec));
	// for_each(all(vec), [](auto i){cout<< i << " ";});
	// mth digt
	int ans = 0;
	for (int i = 0 ; i< n; i ++) {
		// trace(dp[i][m-1]); trace(n-i);
		ans  = ans +( vec[i]*(n-i))%mod ;
		ans%=mod;
	}

	outpos(ans%mod);LN;

}


#include <bits/stdc++.h>
#define inchar			getchar
#define outchar(x)		putchar(x)
#define ll long long
#define int long long //
#define all(v) v.begin(), v.end()
#define SP outchar(' ')
#define trace(x) cerr<<#x<<": "<<x<<" "<<endl;
#define LN outchar('\n')
#define endl '\n'
using namespace std;

template<typename T> void inpos(T &x){x=0;register T c=inchar();while(((c<48)||(c>57))&&(c!='-'))c=inchar();bool neg=0; if(c=='-')neg=1;for(;c<48||c>57;c=inchar());for(;c>47&&c<58;c=inchar())x=(x<<3)+(x<<1)+(c&15);if(neg)x=-x;}
template<typename T> void outpos(T n){if(n<0){outchar('-');n*=-1;}char snum[65];int i=0;do{snum[i++]=n%10+'0';n/=10;}while(n);i=i-1;while(i>=0)outchar(snum[i--]);}
inline void instr(char *str){register char c=0;register int i=0;while(c<33)c=inchar();while(c!='\n'&&c!=' '&&c!=EOF){str[i]=c;c=inchar();++i;}str[i]='\0';}

const int mod = 1e9 + 7;

int dp[1005][15];

int32_t main () {
	int n ; int m;
	inpos(n); inpos(m);

	//number of ways to reach by only taking down and right
	dp[0][0] = 1;

	for (int i = 0; i<n;i++) {
		for (int j = 0; j<m;j++) {
			if (i==0 && j == 0) {
				dp[i][j] = 1;
				// cout << 1 << " ";
				continue;}
			int A = (i-1>=0)?dp[i-1][j]:0;
			int B = (j-1>=0)?dp[i][j-1]:0;
			dp[i][j] = (A +B)%mod;
			// cout << dp[i][j] << " ";
		}
		// cout << endl;
	}
	vector<int> vec;
	for (int i = 0; i<n;i++) {
		vec.push_back(dp[i][m-1]);
	}
	reverse(all(vec));
	// for_each(all(vec), [](auto i){cout<< i << " ";});
	// mth digt
	int ans = 0;
	for (int i = 0 ; i< n; i ++) {
		// trace(dp[i][m-1]); trace(n-i);
		ans  = ans +( vec[i]*(n-i))%mod ;
		ans%=mod;
	}

	outpos(ans%mod);LN;

}


#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define MOD 1000000007

int main()
{
	ll i, j, n, m;
	cin>>n>>m;
	ll  x = n-1+2*m, y = 2*m;
	ll d[x+1][y+1];
	d[0][0] = 1;

	for(i = 1; i <= x; i++)
	{
		for(j = 0; j <= min(i, y); j++)
		{
			if((i == j)||(j == 0))
				d[i][j] = 1;
			else
				d[i][j] = (d[i-1][j] + d[i-1][j-1] )%MOD;
		}
	}

	cout<<d[x][y];

	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define MOD 1000000007

int main()
{
	int i, j, n, m;
	cin>>n>>m;
	ll  x = n-1+2*m, y = 2*m;
	ll d[x+1][y+1];
	d[0][0] = 1;

	for(i = 1; i <= x; i++)
	{
		for(j = 0; j <= min(i, y); j++)
		{
			if((i == j)||(j == 0))
				d[i][j] = 1;
			else
				d[i][j] = (d[i-1][j] + d[i-1][j-1] )%MOD;
		}
	}

	cout<<d[x][y];

	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define MOD 1000000007

int main()
{
	int i, j, n, m;
	cin>>n>>m;
	ll  x = n-1+2*m, y = 2*m;
	ll d[x+1][y+1];
	d[0][0] = 1;

	for(i = 1; i <= x; i++)
	{
		for(j = 0; j <= (i, y); j++)
		{
			if((i == j)||(j == 0))
				d[i][j] = 1;
			else
				d[i][j] = (d[i-1][j] + d[i-1][j-1] )%MOD;
		}
	}

	cout<<d[x][y];

	return 0;
}


    #include<bits/stdc++.h>
    //#include<conio.h>
    using namespace std;

    #define ff first
    #define ss second
    #define int long long
    #define pii pair<int,int>
    #define vi vector<int>
    #define vii vector<pii>
    #define pb push_back
    #define mp make_pair
    #define endl "\n"      // Comment in INTERACTIVE(there just use endl which flushes output , no need of fflush(sdtout)).
    //  for counting setbits -> __builtin_popcountll(x)
    // for counting zerobits -> __builtin_ctzll(x)
    #define fastio() ios_base::sync_with_stdio(false);        cin.tie(NULL); //(unties i/o buffer).
                // DON'T USE SCANF/PRINTF WITH IT (c/c++ -> seperates buffer).

    const int mod = 1000000007;
     const int N = 2*(1e5) + 2;
     int arr[N];

    int fastExp(int base, int exp){
        int res = 1;
        while(exp > 0){
            if(exp & 1)
                res = (1ll * res * base) % mod;     // typecast as may overflow when multiplying .
            base = (1ll * base* base) % mod;
            exp /= 2;
        }
        return res;
    }

    int inversep(int a,int mod){   // If ** MOD IS PRIME  , inv(a) % mod , same as a^(mod -2)
        return fastExp(a,mod - 2);
    }

    int ee(int a, int b,int &x, int &y){  // extended euler function.
    	// assuming both not equal to 0
    	// ** not neccesary a > b
    	if(!b){
    		x = 1;
    		y = 0;
    		return a;
    	}
    	int gcd = ee(b, a% b,x,y);
    	int t = x;
    	x = y;
    	y = t - (a/b)*y;
    	return gcd;    // the gcd.
    	// Complexity same as gcd (same sequence of steps).
    }

    int inverse(int a,int m){
        int x,y;
        int d = ee(a,m,x,y);
        if(d != 1)           // CO - PRIME a AND m , gcd should be 1 , to find multiplicative inverse.
            return -1;
        if(x < 0)            // abs(x) < m , so if -ve , just add m.
            x += m;
        return x;
    }

    int assign(int n,int val){
        int ch = 1, put = 1;
        int ans = 0;
        for(int p = 0;p <= min(n,val); ++p){

            ans = (ans + (ch * put) % mod) % mod;

            int mmi = inverse(p + 1,mod);
            ch = (ch * (val - p)) % mod;
            ch = (ch * mmi) % mod;

            put = (put * (n - p)) % mod;
            put = (put * mmi) % mod;

        }
        return ans;
    }

    int32_t main(){
        fastio();

        #ifndef ONLINE_JUDGE
         freopen("input.txt", "r", stdin);
         freopen("output.txt", "w", stdout);
        #endif

         // ***** AC_chahiye EK BAR MEIN

         // BEGIN CODE HERE
        int n, m;
        cin>>n >>m;

        for(int i = 0;i < n; ++i){
            arr[i] = assign(m - 1,i);
           // cout<<arr[i]<<" ";
        }
        //cout<<endl;
        int ans = 0;
        for(int b = 1;b <= n; ++b){    // assign larger than b
            int cnt1 = assign(m - 1,n - b);//arr[n - b];
            for(int a =1;a <= b ;++a){
                int cnt2 = assign(m - 1,a - 1);//arr[a - 1];

                ans = ans + (cnt1 * cnt2) %mod;
                ans %= mod;
            }
        }
        cout<<ans<<endl;
        //getch();
    }


#include<bits/stdc++.h>
//#include<conio.h>
using namespace std;

#define ff first
#define ss second
#define int long long
#define pii pair<int,int>
#define vi vector<int>
#define vii vector<pii>
#define pb push_back
#define mp make_pair
#define endl "\n"      // Comment in INTERACTIVE(there just use endl which flushes output , no need of fflush(sdtout)).
//  for counting setbits -> __builtin_popcountll(x)
// for counting zerobits -> __builtin_ctzll(x)
#define fastio() ios_base::sync_with_stdio(false);        cin.tie(NULL); //(unties i/o buffer).
            // DON'T USE SCANF/PRINTF WITH IT (c/c++ -> seperates buffer).

const int mod = 1000000007;
 const int N = 2*(1e5) + 2;
 int arr[N];

int fastExp(int base, int exp){
    int res = 1;
    while(exp > 0){
        if(exp & 1)
            res = (1ll * res * base) % mod;     // typecast as may overflow when multiplying .
        base = (1ll * base* base) % mod;
        exp /= 2;
    }
    return res;
}

int inversep(int a,int mod){   // If ** MOD IS PRIME  , inv(a) % mod , same as a^(mod -2)
    return fastExp(a,mod - 2);
}

int assign(int n,int val){
    int ch = 1, put = 1;
    int ans = 0;
    for(int p = 0;p <= min(n,val); ++p){

        ans = (ans + (ch * put) % mod) % mod;

        int mmi = inversep(p + 1,mod);
        ch = (ch * (val - p)) % mod;
        ch = (ch * mmi) % mod;

        put = (put * (n - p)) % mod;
        put = (put * mmi) % mod;

    }
    return ans;
}

int32_t main(){
    fastio();

    #ifndef ONLINE_JUDGE
     freopen("input.txt", "r", stdin);
     freopen("output.txt", "w", stdout);
    #endif

     // ***** AC_chahiye EK BAR MEIN

     // BEGIN CODE HERE
    int n, m;
    cin>>n >>m;

    for(int i = 0;i < n; ++i){
        arr[i] = assign(m - 1,i);
       // cout<<arr[i]<<" ";
    }
    //cout<<endl;
    int ans = 0;
    for(int b = 1;b <= n; ++b){    // assign larger than b
        int cnt1 = assign(m - 1,n - b);//arr[n - b];
        for(int a =1;a <= b ;++a){
            int cnt2 = assign(m - 1,a - 1);//arr[a - 1];

            ans = ans + (cnt1 * cnt2) %mod;
            ans %= mod;
        }
    }
    cout<<ans<<endl;
    //getch();
}


#include<bits/stdc++.h>
//#include<conio.h>
using namespace std;

#define ff first
#define ss second
#define int long long
#define pii pair<int,int>
#define vi vector<int>
#define vii vector<pii>
#define pb push_back
#define mp make_pair
#define endl "\n"      // Comment in INTERACTIVE(there just use endl which flushes output , no need of fflush(sdtout)).
//  for counting setbits -> __builtin_popcountll(x)
// for counting zerobits -> __builtin_ctzll(x)
#define fastio() ios_base::sync_with_stdio(false);        cin.tie(NULL); //(unties i/o buffer).
            // DON'T USE SCANF/PRINTF WITH IT (c/c++ -> seperates buffer).

const int mod = 1000000007;
 const int N = 2*(1e5) + 2;
 int arr[N];

int fastExp(int base, int exp){
    int res = 1;
    while(exp > 0){
        if(exp & 1)
            res = (1ll * res * base) % mod;     // typecast as may overflow when multiplying .
        base = (1ll * base* base) % mod;
        exp /= 2;
    }
    return res;
}

int inversep(int a,int mod){   // If ** MOD IS PRIME  , inv(a) % mod , same as a^(mod -2)
    return fastExp(a,mod - 2);
}

int assign(int n,int val){
    int ch = 1, put = 1;
    int ans = 0;
    for(int p = 0;p <= min(n,val); ++p){

        ans = (ans + (ch * put) % mod) % mod;

        int mmi = inversep(p + 1,mod);
        ch = (ch * (val - p)) % mod;
        ch = (ch * mmi) % mod;

        put = (put * (n - p)) % mod;
        put = (put * mmi) % mod;

    }
    return ans;
}

int nCr(int n,int r,int mod){
    int res = 1;
    for(int i = 0;i < r; ++i){
        res *= n-i;
        res %= mod;

        res *= inversep(i + 1,mod);
        res %= mod;
    }
    return res;
}

int32_t main(){
    fastio();

    #ifndef ONLINE_JUDGE
     freopen("input.txt", "r", stdin);
     freopen("output.txt", "w", stdout);
    #endif

     // ***** AC_chahiye EK BAR MEIN

     // BEGIN CODE HERE
    int n, m;
    cin>>n >>m;

    cout<<nCr(n + 2*m -1,2*m,mod);

    // for(int i = 0;i < n; ++i){
    //     arr[i] = assign(m - 1,i);
    //    // cout<<arr[i]<<" ";
    // }
    // //cout<<endl;
    // int ans = 0;
    // for(int b = 1;b <= n; ++b){    // assign larger than b
    //     int cnt1 = arr[n - b];
    //     for(int a =1;a <= b ;++a){
    //         int cnt2 = arr[a - 1];

    //         ans = ans + (cnt1 * cnt2) %mod;
    //         ans %= mod;
    //     }
    // }
    // cout<<ans<<endl;
    //getch();
}


#include<bits/stdc++.h>
//#include<conio.h>
using namespace std;

#define ff first
#define ss second
#define int long long
#define pii pair<int,int>
#define vi vector<int>
#define vii vector<pii>
#define pb push_back
#define mp make_pair
#define endl "\n"      // Comment in INTERACTIVE(there just use endl which flushes output , no need of fflush(sdtout)).
//  for counting setbits -> __builtin_popcountll(x)
// for counting zerobits -> __builtin_ctzll(x)
#define fastio() ios_base::sync_with_stdio(false);        cin.tie(NULL); //(unties i/o buffer).
            // DON'T USE SCANF/PRINTF WITH IT (c/c++ -> seperates buffer).

const int mod = 1000000007;
 const int N = 2*(1e5) + 2;
 int arr[N];

int fastExp(int base, int exp){
    int res = 1;
    while(exp > 0){
        if(exp & 1)
            res = (1ll * res * base) % mod;     // typecast as may overflow when multiplying .
        base = (1ll * base* base) % mod;
        exp /= 2;
    }
    return res;
}

int inversep(int a,int mod){   // If ** MOD IS PRIME  , inv(a) % mod , same as a^(mod -2)
    return fastExp(a,mod - 2);
}

int assign(int n,int val){
    int ch = 1, put = 1;
    int ans = 0;
    for(int p = 0;p <= min(n,val); ++p){

        ans = (ans + (ch * put) % mod) % mod;

        int mmi = inversep(p + 1,mod);
        ch = (ch * (val - p)) % mod;
        ch = (ch * mmi) % mod;

        put = (put * (n - p)) % mod;
        put = (put * mmi) % mod;

    }
    return ans;
}

int32_t main(){
    fastio();

    #ifndef ONLINE_JUDGE
     freopen("input.txt", "r", stdin);
     freopen("output.txt", "w", stdout);
    #endif

     // ***** AC_chahiye EK BAR MEIN

     // BEGIN CODE HERE
    int n, m;
    cin>>n >>m;

    for(int i = 0;i < n; ++i){
        arr[i] = assign(m - 1,i);
       // cout<<arr[i]<<" ";
    }
    //cout<<endl;
    int ans = 0;
    for(int b = 1;b <= n; ++b){    // assign larger than b
        int cnt1 = arr[n - b];
        for(int a =1;a <= b ;++a){
            int cnt2 = arr[a - 1];

            ans = ans + (cnt1 * cnt2) %mod;
            ans %= mod;
        }
    }
    cout<<ans<<endl;
    //getch();
}


#include<bits/stdc++.h>
//#include<conio.h>
using namespace std;

#define ff first
#define ss second
#define int long long
#define pii pair<int,int>
#define vi vector<int>
#define vii vector<pii>
#define pb push_back
#define mp make_pair
#define endl "\n"      // Comment in INTERACTIVE(there just use endl which flushes output , no need of fflush(sdtout)).
//  for counting setbits -> __builtin_popcountll(x)
// for counting zerobits -> __builtin_ctzll(x)
#define fastio() ios_base::sync_with_stdio(false);        cin.tie(NULL); //(unties i/o buffer).
            // DON'T USE SCANF/PRINTF WITH IT (c/c++ -> seperates buffer).

const int mod = 1000000007;
 const int N = 2*(1e5) + 2;
 int arr[N];

int fastExp(int base, int exp){
    int res = 1;
    while(exp > 0){
        if(exp & 1)
            res = (1ll * res * base) % mod;     // typecast as may overflow when multiplying .
        base = (1ll * base* base) % mod;
        exp /= 2;
    }
    return res;
}

int inversep(int a,int mod){   // If ** MOD IS PRIME  , inv(a) % mod , same as a^(mod -2)
    return fastExp(a,mod - 2);
}

int ee(int a, int b,int &x, int &y){  // extended euler function.
	// assuming both not equal to 0
	// ** not neccesary a > b
	if(!b){
		x = 1;
		y = 0;
		return a;
	}
	int gcd = ee(b, a% b);
	int t = x;
	x = y;
	y = t - (a/b)*y;
	return gcd;    // the gcd.
	// Complexity same as gcd (same sequence of steps).
}

int inverse(int a,int m){
    int x,y;
    int d = ee(a,m,x,y);
    if(d != 1)           // CO - PRIME a AND m , gcd should be 1 , to find multiplicative inverse.
        return -1;
    if(x < 0)            // abs(x) < m , so if -ve , just add m.
        x += m;
    return x;
}

int assign(int n,int val){
    int ch = 1, put = 1;
    int ans = 0;
    for(int p = 0;p <= min(n,val); ++p){

        ans = (ans + (ch * put) % mod) % mod;

        int mmi = inverse(p + 1,mod);
        ch = (ch * (val - p)) % mod;
        ch = (ch * mmi) % mod;

        put = (put * (n - p)) % mod;
        put = (put * mmi) % mod;

    }
    return ans;
}

int32_t main(){
    fastio();

    #ifndef ONLINE_JUDGE
     freopen("input.txt", "r", stdin);
     freopen("output.txt", "w", stdout);
    #endif

     // ***** AC_chahiye EK BAR MEIN

     // BEGIN CODE HERE
    int n, m;
    cin>>n >>m;

    for(int i = 0;i < n; ++i){
        arr[i] = assign(m - 1,i);
       // cout<<arr[i]<<" ";
    }
    //cout<<endl;
    int ans = 0;
    for(int b = 1;b <= n; ++b){    // assign larger than b
        int cnt1 = assign(m - 1,n - b);//arr[n - b];
        for(int a =1;a <= b ;++a){
            int cnt2 = assign(m - 1,a - 1);//arr[a - 1];

            ans = ans + (cnt1 * cnt2) %mod;
            ans %= mod;
        }
    }
    cout<<ans<<endl;
    //getch();
}


#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int M=1e9+7;
int dp[1001][13];

int32_t main(){
    IOS;

    int n,m;cin>>n>>m;

    dp[1][1]=1;
   for(int i=2;i<=n;i++)
   dp[i][1]+=dp[i-1][1]+1;

   for(int i=1;i<=n;i++)
   for(int j=2;j<=12;j++)
   dp[i][j]=(dp[i][j]+dp[i][j-1]+dp[i-1][j])%M;

    int ans=0;

    for(int i=1;i<=n;i++){
    	ans=(ans+(((dp[i][m]-dp[i-1][m]+M)%M)*dp[n-i+1][m])%M)%M;
    	// ans=(ans+(((dp[i][m]-dp[i-1][m]+M)%M)*(dp[n-i+1][m]))%M)%M;
    }
    cout<<ans<<endl;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;

const int MOD = 1e9 + 7;
int ae[12][1002]; // ae[i][j] = num of ASCENDING arrays length (j) with last element = (i)

int main() {
	int n, m;
	cin >> n >> m;

	ae[0][1] = 1;
	long long pre;
	for (int len = 1; len <= m; len++) {
		pre = 0;
		for (int last = 1; last <= n; last++) {
			pre = (pre + ae[len - 1][last]) % MOD;
			ae[len][last] = pre;
		}
	}

	int sum = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = i; j <= n; j++) {
			sum = (1LL * ae[m][i] * ae[m][n - j + 1] + sum) % MOD;
		}
	}
	cout << sum << "\n";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;

void debug_out() { cerr << "\n"; }
template <typename H, typename... T>
void debug_out(H h, T... t) { cerr << " " << (h); debug_out(t...); }
#define DEBUG(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)

const int MOD = 1e9 + 7;
int ae[12][1002]; // ae[i][j] = num of ASCENDING arrays length (j) with last element = (i)
int de[12][1002]; // de[i][j] = num of DESCENDING arrays length (j) with last element = (i)
int pae[12][1002];
int pde[12][1002];

int main() {
	int n, m;
	cin >> n >> m;
		ae[0][1] = de[0][n] = 1;
		long long pre;
		for (int len = 1; len <= m; len++) {
			pre = 0;
			for (int last = 1; last <= n; last++) {
				pre = (pre + ae[len - 1][last]) % MOD;
				ae[len][last] = pre;
			}
			pre = 0;
			for (int last = n; last >= 1; last--) {
				pre = (pre + de[len - 1][last]) % MOD;
				de[len][last] = pre;
			}
		}
	int sum = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = i; j <= n; j++) {
			sum = (1LL * ae[m][i] * de[m][j] + sum) % MOD;
		}
	}
	cout << sum << "\n";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;

const int MOD = 1e9 + 7;
int ae[12][1002]; // ae[i][j] = num of ASCENDING arrays length (j) with last element = (i)
int de[12][1002]; // de[i][j] = num of DESCENDING arrays length (j) with last element = (i)

int main() {
	int n, m;
	cin >> n >> m;

	ae[0][1] = de[0][n] = 1;
	long long pre;
	for (int len = 1; len <= m; len++) {
		pre = 0;
		for (int last = 1; last <= n; last++) {
			pre = (pre + ae[len - 1][last]) % MOD;
			ae[len][last] = pre;
		}
		pre = 0;
		for (int last = n; last >= 1; last--) {
			pre = (pre + de[len - 1][last]) % MOD;
			de[len][last] = pre;
		}
	}

	int sum = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = i; j <= n; j++) {
			sum = (1LL * ae[m][i] * ae[m][n - j + 1] + sum) % MOD;
		}
	}
	cout << sum << "\n";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;

const int MOD = 1e9 + 7;
int ae[12][1002]; // ae[i][j] = num of ASCENDING arrays length (i) with last element = (j)
                  // AND ALSO = num of DESCENDING arrays length (i) with last element = (n-j+1)

int main() {
	int n, m;
	cin >> n >> m;

	ae[0][1] = 1;
	int pre;
	for (int len = 1; len <= m; len++) {
		pre = 0;
		for (int last = 1; last <= n; last++) {
			pre = (0LL + pre + ae[len - 1][last]) % MOD;
			ae[len][last] = pre;
		}
	}

	int sum = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = i; j <= n; j++) {
			sum = (1LL * ae[m][i] * ae[m][n - j + 1] + sum) % MOD;
		}
	}
	cout << sum << "\n";
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
#define FOR(i, a, b) for(int i = (a); i < (b); ++i)
#define FORR(i, a, b) for(int i = (a); i > (b); --i)
#define REP(i, n) for(int i = 0; i < (n); ++i)
#define REPR(i, n) for(int i = n; i >= 0; i--)
#define FOREACH(x, a) for(auto &(x) : (a))
#define VECCIN(x)                                                              \
    for(auto &youso_ : (x)) cin >> youso_
#define bitcnt(x) __builtin_popcount(x)
#define lbit(x) __builtin_ffsll(x)
#define rbit(x) (64 - __builtin_clzll(x))
#define fi first
#define se second
#define All(a) (a).begin(), (a).end()
#define rAll(a) (a).rbegin(), (a).rend()
#define cinfast() cin.tie(0), ios::sync_with_stdio(false)
#define PERM(c)                                                                \
    sort(All(c));                                                              \
    for(bool cp = true; cp; cp = next_permutation(All(c)))
#define COMB(n, k)                                                             \
    for(ll bit = (1LL << k) - 1; bit < (1LL << n); bit = next_combination(bit))
#define PERM2(n, k)                                                            \
    COMB(n, k) {                                                               \
        vector<int> sel;                                                       \
        for(int bitindex = 0; bitindex < n; bitindex++)                        \
            if(bit >> bitindex & 1) sel.emplace_back(bitindex);                \
        PERM(sel) { Printv(sel); }                                             \
    }
#define MKORDER(n)                                                             \
    vector<int> od(n);                                                         \
    iota(All(od), 0LL);

template <typename T = long long> inline T IN() {
    T x;
    cin >> x;
    return (x);
}
inline void CIN() {}
template <class Head, class... Tail>
inline void CIN(Head &&head, Tail &&... tail) {
    cin >> head;
    CIN(move(tail)...);
}
template <class Head> inline void COUT(Head &&head) { cout << (head) << "\n"; }
template <class Head, class... Tail>
inline void COUT(Head &&head, Tail &&... tail) {
    cout << (head) << " ";
    COUT(forward<Tail>(tail)...);
}

#define CCIN(...)                                                              \
    char __VA_ARGS__;                                                          \
    CIN(__VA_ARGS__)
#define DCIN(...)                                                              \
    double __VA_ARGS__;                                                        \
    CIN(__VA_ARGS__)
#define LCIN(...)                                                              \
    long long __VA_ARGS__;                                                     \
    CIN(__VA_ARGS__)
#define SCIN(...)                                                              \
    string __VA_ARGS__;                                                        \
    CIN(__VA_ARGS__)
#define Printv(v)                                                              \
    {                                                                          \
        REP(hoge, v.size())                                                    \
        cout << v[hoge] << (hoge == v.size() - 1 ? "" : " ");                  \
        cout << "\n";                                                          \
    }
template <typename T = string> inline void eputs(T s) {
    cout << s << "\n";
    exit(0);
}
template <typename A, size_t N, typename T>
void Fill(A (&array)[N], const T &val) {
    std::fill((T *)array, (T *)(array + N), val);
}

long long next_combination(long long sub) {
    long long x = sub & -sub, y = sub + x;
    return (((sub & ~y) / x) >> 1) | y;
}

// generic lambdas
template <typename F>
#if defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard)
[[nodiscard]]
#elif defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 4)
__attribute__((warn_unused_result))
#endif // defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard)
    static inline constexpr decltype(auto)
    fix(F &&f) noexcept {
    return [f = std::forward<F>(f)](auto &&... args) {
        return f(f, std::forward<decltype(args)>(args)...);
    };
}

template <typename T> using PQG = priority_queue<T, vector<T>, greater<T>>;
template <typename T> using PQ = priority_queue<T>;

typedef long long ll;
typedef vector<ll> VL;
typedef vector<VL> VVL;
typedef pair<ll, ll> PL;
typedef vector<PL> VPL;
typedef vector<bool> VB;
typedef vector<double> VD;
typedef vector<string> VS;

const int INF = 1e9;
const int MOD = 1e9 + 7;
// const int MOD = 998244353;
const ll LINF = 1e18;
const ll dw[] = {1, 1, 0, -1, -1, -1, 0, 1};
const ll dh[] = {0, 1, 1, 1, 0, -1, -1, -1};
#define PI 3.141592653589793230
#define EPS 1e-7

const ll NMAX = 1e6;
ll fac[NMAX + 1], inv[NMAX + 1], finv[NMAX + 1];

void cominit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[0] = inv[1] = 1;
    FOR(i, 2, NMAX + 1) {
        fac[i] = fac[i - 1] * i % MOD;
        inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
        finv[i] = finv[i - 1] * inv[i] % MOD;
    }
}

VL ans;

ll comb(ll n, ll k) {
    if(n < k) return 0;
    if(n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}

ll hcomb(ll n, ll k) {
    if(n == 0 && k == 0) return 1;
    return comb(n + k - 1, k);
}
signed main() {
    LCIN(N, M);
    cominit();
    cout << hcomb(N, 2 * M) << "\n";
}


#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
#define FOR(i, a, b) for(int i = (a); i < (b); ++i)
#define FORR(i, a, b) for(int i = (a); i > (b); --i)
#define REP(i, n) for(int i = 0; i < (n); ++i)
#define REPR(i, n) for(int i = n; i >= 0; i--)
#define FOREACH(x, a) for(auto &(x) : (a))
#define VECCIN(x)                                                              \
    for(auto &youso_ : (x)) cin >> youso_
#define bitcnt(x) __builtin_popcount(x)
#define lbit(x) __builtin_ffsll(x)
#define rbit(x) (64 - __builtin_clzll(x))
#define fi first
#define se second
#define All(a) (a).begin(), (a).end()
#define rAll(a) (a).rbegin(), (a).rend()
#define cinfast() cin.tie(0), ios::sync_with_stdio(false)
#define PERM(c)                                                                \
    sort(All(c));                                                              \
    for(bool cp = true; cp; cp = next_permutation(All(c)))
#define COMB(n, k)                                                             \
    for(ll bit = (1LL << k) - 1; bit < (1LL << n); bit = next_combination(bit))
#define PERM2(n, k)                                                            \
    COMB(n, k) {                                                               \
        vector<int> sel;                                                       \
        for(int bitindex = 0; bitindex < n; bitindex++)                        \
            if(bit >> bitindex & 1) sel.emplace_back(bitindex);                \
        PERM(sel) { Printv(sel); }                                             \
    }
#define MKORDER(n)                                                             \
    vector<int> od(n);                                                         \
    iota(All(od), 0LL);

template <typename T = long long> inline T IN() {
    T x;
    cin >> x;
    return (x);
}
inline void CIN() {}
template <class Head, class... Tail>
inline void CIN(Head &&head, Tail &&... tail) {
    cin >> head;
    CIN(move(tail)...);
}
template <class Head> inline void COUT(Head &&head) { cout << (head) << "\n"; }
template <class Head, class... Tail>
inline void COUT(Head &&head, Tail &&... tail) {
    cout << (head) << " ";
    COUT(forward<Tail>(tail)...);
}

#define CCIN(...)                                                              \
    char __VA_ARGS__;                                                          \
    CIN(__VA_ARGS__)
#define DCIN(...)                                                              \
    double __VA_ARGS__;                                                        \
    CIN(__VA_ARGS__)
#define LCIN(...)                                                              \
    long long __VA_ARGS__;                                                     \
    CIN(__VA_ARGS__)
#define SCIN(...)                                                              \
    string __VA_ARGS__;                                                        \
    CIN(__VA_ARGS__)
#define Printv(v)                                                              \
    {                                                                          \
        REP(hoge, v.size())                                                    \
        cout << v[hoge] << (hoge == v.size() - 1 ? "" : " ");                  \
        cout << "\n";                                                          \
    }
template <typename T = string> inline void eputs(T s) {
    cout << s << "\n";
    exit(0);
}
template <typename A, size_t N, typename T>
void Fill(A (&array)[N], const T &val) {
    std::fill((T *)array, (T *)(array + N), val);
}

long long next_combination(long long sub) {
    long long x = sub & -sub, y = sub + x;
    return (((sub & ~y) / x) >> 1) | y;
}

// generic lambdas
template <typename F>
#if defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard)
[[nodiscard]]
#elif defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 4)
__attribute__((warn_unused_result))
#endif // defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard)
    static inline constexpr decltype(auto)
    fix(F &&f) noexcept {
    return [f = std::forward<F>(f)](auto &&... args) {
        return f(f, std::forward<decltype(args)>(args)...);
    };
}

template <typename T> using PQG = priority_queue<T, vector<T>, greater<T>>;
template <typename T> using PQ = priority_queue<T>;

typedef long long ll;
typedef vector<ll> VL;
typedef vector<VL> VVL;
typedef pair<ll, ll> PL;
typedef vector<PL> VPL;
typedef vector<bool> VB;
typedef vector<double> VD;
typedef vector<string> VS;

const int INF = 1e9;
const int MOD = 1e9 + 7;
// const int MOD = 998244353;
const ll LINF = 1e18;
const ll dw[] = {1, 1, 0, -1, -1, -1, 0, 1};
const ll dh[] = {0, 1, 1, 1, 0, -1, -1, -1};
#define PI 3.141592653589793230
#define EPS 1e-7

const ll NMAX = 1e6;
ll fac[NMAX + 1], inv[NMAX + 1], finv[NMAX + 1];

void cominit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[0] = inv[1] = 1;
    FOR(i, 2, NMAX + 1) {
        fac[i] = fac[i - 1] * i % MOD;
        inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
        finv[i] = finv[i - 1] * inv[i] % MOD;
    }
}

VL ans;

ll comb(ll n, ll k) {
    if(n < k) return 0;
    if(n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}

ll hcomb(ll n, ll k) {
    if(n == 0 && k == 0) return 1;
    return comb(n + k - 1, k);
}
signed main() {
    LCIN(N, M);
    cominit();
    ll ans = 0;
    FOR(i, 1, N + 1) FOR(j, i, N + 1) {
        ans += hcomb(i, M - 1) * hcomb(N - j + 1, M - 1) % MOD;
        ans %= MOD;
    }
    cout << ans << "\n";
}


#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
#define FOR(i, a, b) for(int i = (a); i < (b); ++i)
#define FORR(i, a, b) for(int i = (a); i > (b); --i)
#define REP(i, n) for(int i = 0; i < (n); ++i)
#define REPR(i, n) for(int i = n; i >= 0; i--)
#define FOREACH(x, a) for(auto &(x) : (a))
#define VECCIN(x)                                                              \
    for(auto &youso_ : (x)) cin >> youso_
#define bitcnt(x) __builtin_popcount(x)
#define lbit(x) __builtin_ffsll(x)
#define rbit(x) (64 - __builtin_clzll(x))
#define fi first
#define se second
#define All(a) (a).begin(), (a).end()
#define rAll(a) (a).rbegin(), (a).rend()
#define cinfast() cin.tie(0), ios::sync_with_stdio(false)
#define PERM(c)                                                                \
    sort(All(c));                                                              \
    for(bool cp = true; cp; cp = next_permutation(All(c)))
#define COMB(n, k)                                                             \
    for(ll bit = (1LL << k) - 1; bit < (1LL << n); bit = next_combination(bit))
#define PERM2(n, k)                                                            \
    COMB(n, k) {                                                               \
        vector<int> sel;                                                       \
        for(int bitindex = 0; bitindex < n; bitindex++)                        \
            if(bit >> bitindex & 1) sel.emplace_back(bitindex);                \
        PERM(sel) { Printv(sel); }                                             \
    }
#define MKORDER(n)                                                             \
    vector<int> od(n);                                                         \
    iota(All(od), 0LL);

template <typename T = long long> inline T IN() {
    T x;
    cin >> x;
    return (x);
}
inline void CIN() {}
template <class Head, class... Tail>
inline void CIN(Head &&head, Tail &&... tail) {
    cin >> head;
    CIN(move(tail)...);
}
template <class Head> inline void COUT(Head &&head) { cout << (head) << "\n"; }
template <class Head, class... Tail>
inline void COUT(Head &&head, Tail &&... tail) {
    cout << (head) << " ";
    COUT(forward<Tail>(tail)...);
}

#define CCIN(...)                                                              \
    char __VA_ARGS__;                                                          \
    CIN(__VA_ARGS__)
#define DCIN(...)                                                              \
    double __VA_ARGS__;                                                        \
    CIN(__VA_ARGS__)
#define LCIN(...)                                                              \
    long long __VA_ARGS__;                                                     \
    CIN(__VA_ARGS__)
#define SCIN(...)                                                              \
    string __VA_ARGS__;                                                        \
    CIN(__VA_ARGS__)
#define Printv(v)                                                              \
    {                                                                          \
        REP(hoge, v.size())                                                    \
        cout << v[hoge] << (hoge == v.size() - 1 ? "" : " ");                  \
        cout << "\n";                                                          \
    }
template <typename T = string> inline void eputs(T s) {
    cout << s << "\n";
    exit(0);
}
template <typename A, size_t N, typename T>
void Fill(A (&array)[N], const T &val) {
    std::fill((T *)array, (T *)(array + N), val);
}

long long next_combination(long long sub) {
    long long x = sub & -sub, y = sub + x;
    return (((sub & ~y) / x) >> 1) | y;
}

// generic lambdas
template <typename F>
#if defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard)
[[nodiscard]]
#elif defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 4)
__attribute__((warn_unused_result))
#endif // defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard)
    static inline constexpr decltype(auto)
    fix(F &&f) noexcept {
    return [f = std::forward<F>(f)](auto &&... args) {
        return f(f, std::forward<decltype(args)>(args)...);
    };
}

template <typename T> using PQG = priority_queue<T, vector<T>, greater<T>>;
template <typename T> using PQ = priority_queue<T>;

typedef long long ll;
typedef vector<ll> VL;
typedef vector<VL> VVL;
typedef pair<ll, ll> PL;
typedef vector<PL> VPL;
typedef vector<bool> VB;
typedef vector<double> VD;
typedef vector<string> VS;

const int INF = 1e9;
const int MOD = 1e9 + 7;
// const int MOD = 998244353;
const ll LINF = 1e18;
const ll dw[] = {1, 1, 0, -1, -1, -1, 0, 1};
const ll dh[] = {0, 1, 1, 1, 0, -1, -1, -1};
#define PI 3.141592653589793230
#define EPS 1e-7

const ll NMAX = 1e6;
ll fac[NMAX + 1], inv[NMAX + 1], finv[NMAX + 1];

void cominit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[0] = inv[1] = 1;
    FOR(i, 2, NMAX + 1) {
        fac[i] = fac[i - 1] * i % MOD;
        inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
        finv[i] = finv[i - 1] * inv[i] % MOD;
    }
}

VL ans;

ll comb(ll n, ll k) {
    if(n < k) return 0;
    if(n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}

ll hcomb(ll n, ll k) {
    if(n == 0 && k == 0) return 1;
    return comb(n + k - 1, k);
}
signed main() {
    LCIN(N, M);
    cominit();
    ll ans = 0;
    FOR(j, 1, N + 1) {
        ans += hcomb(j, M) * hcomb(N - j + 1, M - 1) % MOD;
        ans %= MOD;
    }
    cout << ans << "\n";
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD=1000000007;
vector<ll>fact(10000);
void cal()
{
    fact[0]=1;
    for(ll i=1; i<1e4; i++)
        fact[i]=(fact[i-1]*i)%MOD;
}
ll bigmod(ll a,ll b)
{
    if(b==0)
        return 1;
    if(b%2==0)
    {
        ll ret=bigmod(a,b/2);
        return (ret*ret)%MOD;
    }
    else
        return ((a%MOD)*bigmod(a,b-1))%MOD;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cal();
    ll n,m,ans;
    cin>>n>>m;
    ans=(bigmod(fact[2*m],MOD-2)*bigmod(fact[n-1],MOD-2))%MOD;
    cout<<(fact[2*m+n-1]*ans)%MOD<<endl;
}


///#pragma GCC optimize("Ofast")
///#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,fma")
///#pragma GCC optimize("unroll-loops")

#include<bits/stdc++.h>
///#include<ext/pb_ds/assoc_container.hpp>
///#include<ext/pb_ds/tree_policy.hpp>
using namespace std;
///using namespace __gnu_pbds;
///template<typename T> using orderset = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;

typedef long long ll;
typedef vector<int> vii;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef vector<vii> vvii;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const ll N = 100001;
const ll MOD = 1000000007;
const ll INF = LLONG_MAX;

#define all(a) a.begin(),a.end()
#define rall(a) a.rbegin(),a.rend()
#define rev(a) reverse(all(a))
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define yes cout<<"YES"<<nl
#define no cout<<"NO"<<nl
#define space ' '
#define nl '\n'
#define PI acos(-1)
#define Case(x) cout<<"Case "<<x<<": "

#define coutv(v) for(auto it:v)cout<<it<<space;cout<<nl;
#define cinv(v) for(auto &it:v)cin>>it;

int main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int tc=1,cs=0;
    //cin>>tc;
    while(tc--)
    {
        ll n,m,i,j;
        cin>>n>>m;
        vvll dp(2*m+1,vll(n+1));
        for(i=1; i<=n; i++)
            dp[0][i]=1;
        for(i=1; i<=2*m; i++)
            for(j=1; j<=n; j++)
                dp[i][j]=(dp[i-1][j]+dp[i][j-1])%MOD;
        cout<<dp[2*m][n]<<nl;
    }
}


///#pragma GCC optimize("Ofast")
///#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,fma")
///#pragma GCC optimize("unroll-loops")

#include<bits/stdc++.h>
///#include<ext/pb_ds/assoc_container.hpp>
///#include<ext/pb_ds/tree_policy.hpp>
using namespace std;
///using namespace __gnu_pbds;
///template<typename T> using orderset = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;

typedef long long ll;
typedef vector<int> vii;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef vector<vii> vvii;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const ll N = 200001;
const ll MOD = 1000000007;
const ll INF = LLONG_MAX;

#define all(a) a.begin(),a.end()
#define rall(a) a.rbegin(),a.rend()
#define rev(a) reverse(all(a))
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define yes cout<<"YES"<<nl
#define no cout<<"NO"<<nl
#define space ' '
#define nl '\n'
#define PI acos(-1)
#define cse(x) cout<<"Case "<<x<<": "

#define coutv(v) for(auto it:v)cout<<it<<space;cout<<nl;
#define cinv(v) for(auto &it:v)cin>>it;

ll dp[1005][22];

ll Calculation(ll len,ll n)
{
    if(len==0||n==1)
        return 1;
    if(dp[len][n]!=-1)
        return dp[len][n];
    return dp[len][n]=(Calculation(len-1,n)+Calculation(len,n-1))%MOD;
}

int main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int tc=1,cs=0;
    //cin>>tc;
    while(tc--)
    {
        ll n,m;
        cin>>n>>m;
        memset(dp,-1,sizeof dp);
        cout<<Calculation(2*m,n)<<nl;
    }
}


///#pragma GCC optimize("Ofast")
///#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,fma")
///#pragma GCC optimize("unroll-loops")

#include<bits/stdc++.h>
///#include<ext/pb_ds/assoc_container.hpp>
///#include<ext/pb_ds/tree_policy.hpp>
using namespace std;
///using namespace __gnu_pbds;
///template<typename T> using orderset = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;

typedef long long ll;
typedef vector<int> vii;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef vector<vii> vvii;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const ll N = 200001;
const ll MOD = 1000000007;
const ll INF = LLONG_MAX;

#define all(a) a.begin(),a.end()
#define rall(a) a.rbegin(),a.rend()
#define rev(a) reverse(all(a))
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define yes cout<<"YES"<<nl
#define no cout<<"NO"<<nl
#define space ' '
#define nl '\n'
#define PI acos(-1)
#define cse(x) cout<<"Case "<<x<<": "

#define coutv(v) for(auto it:v)cout<<it<<space;cout<<nl;
#define cinv(v) for(auto &it:v)cin>>it;

ll dp[21][1001];

ll Calculation(ll len,ll n)
{
    if(len==0||n==1)
        return 1;
    if(dp[len][n]!=-1)
        return dp[len][n];
    return dp[len][n]=(Calculation(len-1,n)+Calculation(len,n-1))%MOD;
}

int main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int tc=1,cs=0;
    //cin>>tc;
    while(tc--)
    {
        ll n,m;
        cin>>n>>m;
        memset(dp,-1,sizeof dp);
        cout<<Calculation(2*m,n)<<nl;
    }
}


///#pragma GCC optimize("Ofast")
///#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,fma")
///#pragma GCC optimize("unroll-loops")

#include<bits/stdc++.h>
///#include<ext/pb_ds/assoc_container.hpp>
///#include<ext/pb_ds/tree_policy.hpp>
using namespace std;
///using namespace __gnu_pbds;
///template<typename T> using orderset = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;

typedef long long ll;
typedef vector<int> vii;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef vector<vii> vvii;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const ll N = 200001;
const ll MOD = 1000000007;
const ll INF = LLONG_MAX;

#define all(a) a.begin(),a.end()
#define rall(a) a.rbegin(),a.rend()
#define rev(a) reverse(all(a))
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define yes cout<<"YES"<<nl
#define no cout<<"NO"<<nl
#define space ' '
#define nl '\n'
#define PI acos(-1)
#define cse(x) cout<<"Case "<<x<<": "

#define coutv(v) for(auto it:v)cout<<it<<space;cout<<nl;
#define cinv(v) for(auto &it:v)cin>>it;

ll dp[1001][21];

ll Calculation(ll len,ll n)
{
    if(len==0||n==1)
        return 1;
    if(dp[len][n]!=-1)
        return dp[len][n];
    return dp[len][n]=(Calculation(len-1,n)+Calculation(len,n-1))%MOD;
}

int main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int tc=1,cs=0;
    //cin>>tc;
    while(tc--)
    {
        ll n,m;
        cin>>n>>m;
        memset(dp,-1,sizeof dp);
        cout<<Calculation(2*m,n)<<nl;
    }
}


//include <paBezanAshghal>
#include <bits/stdc++.h>
#define 	Time 	        	printf("\nTime : %.3lf s.\n", clock()*1.0/CLOCKS_PER_SEC)
#define 	For(J,R,K)       	for(int J=R;J<K;++J)
#define 	Rep(I,N)         	For(I,0,N)
#define 	MP 		        	make_pair
#define 	ALL(X)       		(X).begin(),(X).end()
#define 	SF 	        		scanf
#define 	PF 		        	printf
#define 	pii         		pair<long long,long long>
#define 	piii         		pair<  long long , pii  >
#define 	pdd             		pair<double , double>
#define 	Sort(v) 	        sort(ALL(v))
#define     GSORT(x)            sort(ALL(x), greater<typeof(*((x).begin()))>())
#define 	Test 		        freopen("a.in","r",stdin)
#define 	Testout 	        freopen("a.out","w",stdout)
#define     UNIQUE(v)           Sort(v); (v).reeize(unique(ALL(v)) - (v).begin())
#define 	pb 		        	push_back
#define 	Set(a,n)        	memset(a,n,sizeof(a))
#define 	MAXN 		        100000+99
#define 	EPS 		        1e-7
#define 	inf 		        1ll<<61
#define     SF                  scanf
#define     PF                  printf
#define     F                   first
#define     S                   second
#define 	vpii         		vector<pii>
#define 	vll        		    vector<ll>
#define     booste              ios_base::sync_with_stdio(NULL); cin.tie(NULL); cout.tie(NULL);
typedef long long ll;
typedef long double ld;
using namespace std;
inline ll get_num(char ch){
    if(ch == '-')return 0;
    else if(ch >= 'a' && ch <= 'z'){
        return 1 + (ch-'a');
    }
    else if(ch >= 'A' && ch <= 'Z'){
        return 27 +(ch - 'A');
    }
    else if(ch >= '0' && ch <= '9'){
        return 53 +(ch - '0');
    }
}
//inline ll pw(ll x ,ll y){
//    if(y==0) return 1;
//    ll p = pw(x ,y/2);
//    p*=p;
//    if(y&1) p*=x;
//    return p;
//}
 int dx[] = {1,0,-1, 0} , dy[] = {0,1, 0, -1};  // 4 Direction
//int dx[] = {1,0,-1, 0 , 2 ,0 ,-2, 0 , 3 ,0 ,-3 ,0} ,
 //   dy[] = {0,1, 0, -1 , 0 ,2 ,0 , -2 , 0 , 3, 0 , -3};  // 4 Direction

 //int dx[] = {1,-1,0,0,1,1,-1,-1} , dy[] = {0,0,1,-1,1,-1,1,-1}; // 8 Direction
/* int dx[] = {1,-1,1,-1,2,2,-2,-2} , dy[] = {2,2,-2,-2,1,-1,1,-1}; */ // Knight Direction
/* int dx[] = {2,-2,1,1,-1,-1} , dy[] = {0,0,1,-1,1,-1}; */ // Hexagonal Direction
inline int GA(ll n , vector<ll>&vec){
    Rep(i ,n){ll x ;cin>>x ; vec.push_back(x);}
    return 0;
}
inline int GAEG(ll m ,vector<ll>vec[]){
    Rep(i ,m){ll x  , y ;cin>>x>>y ; x-- , y-- ; vec[x].push_back(y); vec[y].push_back(x);}
    return 0;
}
const ll MD =  1000000007;

bool isvalid(ll xx, ll yy , ll n , ll m ){
    return (xx>=0 && xx<n && yy>=0 && yy<m);
}

ll pw(ll x, ll y, ll dr){
    if(y==0) return 1;
    ll o = y/2;
    ll f = pw(x, o , dr)%dr;
    if(y%2){
        return (((f*f)%dr)*x)%dr;
    }
    else return (f*f)%dr;
}

ll ff[2000004];
    ll m , n;
//Stars and Bars
int main(){
    Test;
    ff[0]=1;
    cin>>n>>m;
    For(i ,1, n+2*m+1) ff[i]=ff[i-1]*i  , ff[i]%=MD;
    cout<<(ll)ff[-1+n+2*m]*((pw(ff[2*m] , MD-2 , MD))%MD*pw(ff[n-1] , MD-2, MD)%MD)%MD;

    return 0;
}


//include <paBezanAshghal>
#include <bits/stdc++.h>
#define 	Time 	        	printf("\nTime : %.3lf s.\n", clock()*1.0/CLOCKS_PER_SEC)
#define 	For(J,R,K)       	for(int J=R;J<K;++J)
#define 	Rep(I,N)         	For(I,0,N)
#define 	MP 		        	make_pair
#define 	ALL(X)       		(X).begin(),(X).end()
#define 	SF 	        		scanf
#define 	PF 		        	printf
#define 	pii         		pair<long long,long long>
#define 	piii         		pair<  long long , pii  >
#define 	pdd             		pair<double , double>
#define 	Sort(v) 	        sort(ALL(v))
#define     GSORT(x)            sort(ALL(x), greater<typeof(*((x).begin()))>())
#define 	Test 		        freopen("a.in","r",stdin)
#define 	Testout 	        freopen("a.out","w",stdout)
#define     UNIQUE(v)           Sort(v); (v).reeize(unique(ALL(v)) - (v).begin())
#define 	pb 		        	push_back
#define 	Set(a,n)        	memset(a,n,sizeof(a))
#define 	MAXN 		        100000+99
#define 	EPS 		        1e-7
#define 	inf 		        1ll<<61
#define     SF                  scanf
#define     PF                  printf
#define     F                   first
#define     S                   second
#define 	vpii         		vector<pii>
#define 	vll        		    vector<ll>
#define     booste              ios_base::sync_with_stdio(NULL); cin.tie(NULL); cout.tie(NULL);
typedef long long ll;
typedef long double ld;
using namespace std;
inline ll get_num(char ch){
    if(ch == '-')return 0;
    else if(ch >= 'a' && ch <= 'z'){
        return 1 + (ch-'a');
    }
    else if(ch >= 'A' && ch <= 'Z'){
        return 27 +(ch - 'A');
    }
    else if(ch >= '0' && ch <= '9'){
        return 53 +(ch - '0');
    }
}
//inline ll pw(ll x ,ll y){
//    if(y==0) return 1;
//    ll p = pw(x ,y/2);
//    p*=p;
//    if(y&1) p*=x;
//    return p;
//}
 int dx[] = {1,0,-1, 0} , dy[] = {0,1, 0, -1};  // 4 Direction
//int dx[] = {1,0,-1, 0 , 2 ,0 ,-2, 0 , 3 ,0 ,-3 ,0} ,
 //   dy[] = {0,1, 0, -1 , 0 ,2 ,0 , -2 , 0 , 3, 0 , -3};  // 4 Direction

 //int dx[] = {1,-1,0,0,1,1,-1,-1} , dy[] = {0,0,1,-1,1,-1,1,-1}; // 8 Direction
/* int dx[] = {1,-1,1,-1,2,2,-2,-2} , dy[] = {2,2,-2,-2,1,-1,1,-1}; */ // Knight Direction
/* int dx[] = {2,-2,1,1,-1,-1} , dy[] = {0,0,1,-1,1,-1}; */ // Hexagonal Direction
inline int GA(ll n , vector<ll>&vec){
    Rep(i ,n){ll x ;cin>>x ; vec.push_back(x);}
    return 0;
}
inline int GAEG(ll m ,vector<ll>vec[]){
    Rep(i ,m){ll x  , y ;cin>>x>>y ; x-- , y-- ; vec[x].push_back(y); vec[y].push_back(x);}
    return 0;
}
const ll MD =  1000000007;

bool isvalid(ll xx, ll yy , ll n , ll m ){
    return (xx>=0 && xx<n && yy>=0 && yy<m);
}

ll pw(ll x, ll y, ll dr){
    if(y==0) return 1;
    ll o = y/2;
    ll f = pw(x, o , dr)%dr;
    if(y%2){
        return (((f*f)%dr)*x)%dr;
    }
    else return (f*f)%dr;
}

ll ff[2000004];
    ll m , n;
//Stars and Bars
int main(){
//    Test;
    ff[0]=1;
    cin>>n>>m;
    For(i ,1, n+2*m+1) ff[i]=ff[i-1]*i  , ff[i]%=MD;
    cout<<(ll)ff[n+2*m -1]*((pw(ff[2*m] , MD-2 , MD))%MD*pw(ff[n-1] , MD-2, MD)%MD)%MD;

    return 0;
}


//include <paBezanAshghal>
#include <bits/stdc++.h>
#define 	Time 	        	printf("\nTime : %.3lf s.\n", clock()*1.0/CLOCKS_PER_SEC)
#define 	For(J,R,K)       	for(int J=R;J<K;++J)
#define 	Rep(I,N)         	For(I,0,N)
#define 	MP 		        	make_pair
#define 	ALL(X)       		(X).begin(),(X).end()
#define 	SF 	        		scanf
#define 	PF 		        	printf
#define 	pii         		pair<long long,long long>
#define 	piii         		pair<  long long , pii  >
#define 	pdd             		pair<double , double>
#define 	Sort(v) 	        sort(ALL(v))
#define     GSORT(x)            sort(ALL(x), greater<typeof(*((x).begin()))>())
#define 	Test 		        freopen("a.in","r",stdin)
#define 	Testout 	        freopen("a.out","w",stdout)
#define     UNIQUE(v)           Sort(v); (v).reeize(unique(ALL(v)) - (v).begin())
#define 	pb 		        	push_back
#define 	Set(a,n)        	memset(a,n,sizeof(a))
#define 	MAXN 		        100000+99
#define 	EPS 		        1e-7
#define 	inf 		        1ll<<61
#define     SF                  scanf
#define     PF                  printf
#define     F                   first
#define     S                   second
#define 	vpii         		vector<pii>
#define 	vll        		    vector<ll>
#define     booste              ios_base::sync_with_stdio(NULL); cin.tie(NULL); cout.tie(NULL);
typedef long long ll;
typedef long double ld;
using namespace std;
inline ll get_num(char ch){
    if(ch == '-')return 0;
    else if(ch >= 'a' && ch <= 'z'){
        return 1 + (ch-'a');
    }
    else if(ch >= 'A' && ch <= 'Z'){
        return 27 +(ch - 'A');
    }
    else if(ch >= '0' && ch <= '9'){
        return 53 +(ch - '0');
    }
}
//inline ll pw(ll x ,ll y){
//    if(y==0) return 1;
//    ll p = pw(x ,y/2);
//    p*=p;
//    if(y&1) p*=x;
//    return p;
//}
 int dx[] = {1,0,-1, 0} , dy[] = {0,1, 0, -1};  // 4 Direction
//int dx[] = {1,0,-1, 0 , 2 ,0 ,-2, 0 , 3 ,0 ,-3 ,0} ,
 //   dy[] = {0,1, 0, -1 , 0 ,2 ,0 , -2 , 0 , 3, 0 , -3};  // 4 Direction

 //int dx[] = {1,-1,0,0,1,1,-1,-1} , dy[] = {0,0,1,-1,1,-1,1,-1}; // 8 Direction
/* int dx[] = {1,-1,1,-1,2,2,-2,-2} , dy[] = {2,2,-2,-2,1,-1,1,-1}; */ // Knight Direction
/* int dx[] = {2,-2,1,1,-1,-1} , dy[] = {0,0,1,-1,1,-1}; */ // Hexagonal Direction
inline int GA(ll n , vector<ll>&vec){
    Rep(i ,n){ll x ;cin>>x ; vec.push_back(x);}
    return 0;
}
inline int GAEG(ll m ,vector<ll>vec[]){
    Rep(i ,m){ll x  , y ;cin>>x>>y ; x-- , y-- ; vec[x].push_back(y); vec[y].push_back(x);}
    return 0;
}
const ll MD =  1000000007;

bool isvalid(ll xx, ll yy , ll n , ll m ){
    return (xx>=0 && xx<n && yy>=0 && yy<m);
}

ll pw(ll x, ll y, ll dr){
    if(y==0) return 1;
    ll o = y/2;
    ll f = pw(x, o , dr)%dr;
    if(y%2){
        return (((f*f)%dr)*x)%dr;
    }
    else return (f*f)%dr;
}

ll arr[1001][25];

ll DD(ll x ,ll y){
    if(y==-1) return 1;
    ll &re = arr[x][y];
    if(re != -1) return re;
    ll qq = 0 ;
    For(i ,1, x+1){
            qq+= (DD(i , y-1))%MD;
    }
    return re =qq%MD;
}

int main(){
//    Test;
    ll n ,m ;
    cin>>n>>m;
    Set(arr ,-1);
    cout<<DD(n  , 2*m-1)%MD<<endl;
    return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>

#define ft first
#define sd second
#define pb push_back
#define pf push_front
#define mk make_pair
#define all(c) (c).begin(), (c).end()
#define SWS ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define rfile freopen("input.txt", "r", stdin)
#define wfile freopen("output.txt", "w", stdout)
#define files rfile; wfile
#define DEBUG_VAR(x) #x << " = " << x << ";"
#define DEBUG 1

typedef long long ll;
typedef unsigned long long ull;

using namespace std;

const int Z = 3 * (int)1e5 + 111;
const int INF = (int)1e9 + 111;
const int MODF = 1000000007;

long long C[1111][22];

int main() {
    for (int n = 0; n <= 1100; ++n) {
    	C[n][0] = C[n][n] = 1;
    	for (int k = 1; k < 20; ++k) {
    		C[n][k] = ((!n ? 0 : C[n-1][k-1]) + C[n-1][k]) % MODF;
        }
    }
    SWS;
    int n, m;
    cin >> n >> m;
    m -= 1;
    long long ans = 0;
    for (int a = 1; a <= n; ++a) {
        for (int b = a; b <= n; ++b) {
            int N1 = a;
            int N2 = n - b + 1;
            ans = (ans + C[N1 + m - 1][m] * C[N2 + m - 1][m] % MODF) % MODF;
        }
    }
    cout << ans;

    return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>

#define ft first
#define sd second
#define pb push_back
#define pf push_front
#define mk make_pair
#define all(c) (c).begin(), (c).end()
#define SWS ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define rfile freopen("input.txt", "r", stdin)
#define wfile freopen("output.txt", "w", stdout)
#define files rfile; wfile
#define DEBUG_VAR(x) #x << " = " << x << ";"
#define DEBUG 1

typedef long long ll;
typedef unsigned long long ull;

const int Z = 3 * (int)1e5 + 111;
const int INF = (int)1e9 + 111;
const long long MODF = 1000000007;

long long CC[1111][22];

int main() {
    CC[0][0] = 1;
    for (int n = 1; n <= 1100; ++n) {
    	CC[n][0] = CC[n][n] = 1;
    	for (int k = 1; k < 20; ++k) {
   		    CC[n][k] = ((!n ? 0 : CC[n - 1][k - 1]) + (!n ? 0 : CC[n - 1][k])) % MODF;
        }
    }
    int n, m;
    std::cin >> n >> m;
    m -= 1;
    long long ans = 0;
    for (int a = 1; a <= n; ++a) {
        for (int b = a; b <= n; ++b) {
            int N1 = a;
            int N2 = n - b + 1;
            ans = (ans + CC[N1 + m - 1][m] * CC[N2 + m - 1][m] % MODF) % MODF;
        }
    }
    std::cout << ans;

    return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>

#define ft first
#define sd second
#define pb push_back
#define pf push_front
#define mk make_pair
#define all(c) (c).begin(), (c).end()
#define SWS ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define rfile freopen("input.txt", "r", stdin)
#define wfile freopen("output.txt", "w", stdout)
#define files rfile; wfile
#define DEBUG_VAR(x) #x << " = " << x << ";"
#define DEBUG 1

typedef long long ll;
typedef unsigned long long ull;

using namespace std;

const int Z = 3 * (int)1e5 + 111;
const int INF = (int)1e9 + 111;
const int MODF = 1000000007;

long long C[1111][22];

int main() {
    C[0][0] = 1;
    for (int n = 1; n <= 1100; ++n) {
    	C[n][0] = C[n][n] = 1;
    	for (int k = 1; k < 20; ++k) {
   		    C[n][k] = ((!n ? 0 : C[n - 1][k - 1]) + (!n ? 0 : C[n - 1][k])) % MODF;
        }
    }
    int n, m;
    cin >> n >> m;
    m -= 1;
    long long ans = 0;
    for (int a = 1; a <= n; ++a) {
        for (int b = a; b <= n; ++b) {
            int N1 = a;
            int N2 = n - b + 1;
            ans = (ans + C[N1 + m - 1][m] * C[N2 + m - 1][m] % MODF) % MODF;
        }
    }
    cout << ans;

    return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>

#define ft first
#define sd second
#define pb push_back
#define pf push_front
#define mk make_pair
#define all(c) (c).begin(), (c).end()
#define SWS ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define rfile freopen("input.txt", "r", stdin)
#define wfile freopen("output.txt", "w", stdout)
#define files rfile; wfile
#define DEBUG_VAR(x) #x << " = " << x << ";"
#define DEBUG 1

typedef long long ll;
typedef unsigned long long ull;

const int Z = 3 * (int)1e5 + 111;
const int INF = (int)1e9 + 111;
const long long MODF = 1000000007;

long long CC[Z][111];

int main() {
    CC[0][0] = 1;
    for (int n = 1; n <= 1100; ++n) {
    	CC[n][0] = CC[n][n] = 1;
    	for (int k = 1; k < 20; ++k) {
   		    CC[n][k] = ((!n ? 0 : CC[n - 1][k - 1]) + (!n ? 0 : CC[n - 1][k])) % MODF;
        }
    }
    int n, m;
    std::cin >> n >> m;
    m -= 1;
    long long ans = 0;
    for (int a = 1; a <= n; ++a) {
        for (int b = a; b <= n; ++b) {
            int N1 = a;
            int N2 = n - b + 1;
            ans = (ans + CC[N1 + m - 1][m] * CC[N2 + m - 1][m] % MODF) % MODF;
        }
    }
    std::cout << ans;

    return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>

#define ft first
#define sd second
#define pb push_back
#define pf push_front
#define mk make_pair
#define all(c) (c).begin(), (c).end()
#define SWS ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define rfile freopen("input.txt", "r", stdin)
#define wfile freopen("output.txt", "w", stdout)
#define files rfile; wfile
#define DEBUG_VAR(x) #x << " = " << x << ";"
#define DEBUG 1

typedef long long ll;
typedef unsigned long long ull;

using namespace std;

const int Z = 3 * (int)1e5 + 111;
const int INF = (int)1e9 + 111;
const int MODF = (int)1e9 + 7;

long long C[1111][22];

int main() {
    for (int n = 1; n <= 1100; ++n) {
    	C[n][0] = C[n][n] = 1;
    	for (int k = 1; k < 20; ++k) {
    		C[n][k] = (C[n-1][k-1] + C[n-1][k]) % MODF;
        }
    }
    SWS;
    int n, m;
    cin >> n >> m;
    m -= 1;
    size_t ans = 0;
    for (int a = 1; a <= n; ++a) {
        for (int b = a; b <= n; ++b) {
            int N1 = a;
            int N2 = n - b + 1;
            ans = (ans + C[N1 + m - 1][m] * C[N2 + m - 1][m] % MODF) % MODF;
        }
    }
    cout << ans;

    return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>

#define ft first
#define sd second
#define pb push_back
#define pf push_front
#define mk make_pair
#define all(c) (c).begin(), (c).end()
#define SWS ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define rfile freopen("input.txt", "r", stdin)
#define wfile freopen("output.txt", "w", stdout)
#define files rfile; wfile
#define DEBUG_VAR(x) #x << " = " << x << ";"
#define DEBUG 1

typedef long long ll;
typedef unsigned long long ull;

using namespace std;

const int Z = 3 * (int)1e5 + 111;
const int INF = (int)1e9 + 111;
const int MODF = 1000000007;

long long C[1111][22];

int main() {
    for (int n = 0; n <= 1100; ++n) {
    	C[n][0] = C[n][n] = 1;
    	for (int k = 1; k < 20; ++k) {
   		    C[n][k] = ((!n ? 0 : C[n - 1][k - 1]) + (!n ? 0 : C[n - 1][k])) % MODF;
        }
    }
    int n, m;
    cin >> n >> m;
    m -= 1;
    long long ans = 0;
    for (int a = 1; a <= n; ++a) {
        for (int b = a; b <= n; ++b) {
            int N1 = a;
            int N2 = n - b + 1;
            ans = (ans + C[N1 + m - 1][m] * C[N2 + m - 1][m] % MODF) % MODF;
        }
    }
    cout << ans;

    return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>

#define ft first
#define sd second
#define pb push_back
#define pf push_front
#define mk make_pair
#define all(c) (c).begin(), (c).end()
#define SWS ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define rfile freopen("input.txt", "r", stdin)
#define wfile freopen("output.txt", "w", stdout)
#define files rfile; wfile
#define DEBUG_VAR(x) #x << " = " << x << ";"
#define DEBUG 1

typedef long long ll;
typedef unsigned long long ull;

using namespace std;

const int Z = 3 * (int)1e5 + 111;
const int INF = (int)1e9 + 111;
const int MODF = 1000000007;

long long C[1111][22];

int main() {
    for (int n = 0; n <= 1100; ++n) {
    	C[n][0] = C[n][n] = 1;
    	for (int k = 1; k < 20; ++k) {
    		C[n][k] = ((!n ? 0 : C[n - 1][k - 1]) + C[n - 1][k]) % MODF;
        }
    }
    SWS;
    int n, m;
    cin >> n >> m;
    m -= 1;
    long long ans = 0;
    for (int a = 1; a <= n; ++a) {
        for (int b = a; b <= n; ++b) {
            int N1 = a;
            int N2 = n - b + 1;
            ans = (ans + C[N1 + m - 1][m] * C[N2 + m - 1][m] % MODF) % MODF;
        }
    }
    cout << ans;

    return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>

#define ft first
#define sd second
#define pb push_back
#define pf push_front
#define mk make_pair
#define all(c) (c).begin(), (c).end()
#define SWS ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define rfile freopen("input.txt", "r", stdin)
#define wfile freopen("output.txt", "w", stdout)
#define files rfile; wfile
#define DEBUG_VAR(x) #x << " = " << x << ";"
#define DEBUG 1

typedef long long ll;
typedef unsigned long long ull;

using namespace std;

const int Z = 3 * (int)1e5 + 111;
const int INF = (int)1e9 + 111;
const int MODF = 1000000007;

long long CC[1111][22];

int main() {
    CC[0][0] = 1;
    for (int n = 1; n <= 1100; ++n) {
    	CC[n][0] = CC[n][n] = 1;
    	for (int k = 1; k < 20; ++k) {
   		    CC[n][k] = ((!n ? 0 : CC[n - 1][k - 1]) + (!n ? 0 : CC[n - 1][k])) % MODF;
        }
    }
    int n, m;
    cin >> n >> m;
    m -= 1;
    long long ans = 0;
    for (int a = 1; a <= n; ++a) {
        for (int b = a; b <= n; ++b) {
            int N1 = a;
            int N2 = n - b + 1;
            ans = (ans + CC[N1 + m - 1][m] * CC[N2 + m - 1][m] % MODF) % MODF;
        }
    }
    cout << ans;

    return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>

#define ft first
#define sd second
#define pb push_back
#define pf push_front
#define mk make_pair
#define all(c) (c).begin(), (c).end()
#define SWS ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define rfile freopen("input.txt", "r", stdin)
#define wfile freopen("output.txt", "w", stdout)
#define files rfile; wfile
#define DEBUG_VAR(x) #x << " = " << x << ";"
#define DEBUG 1

typedef long long ll;
typedef unsigned long long ull;

using namespace std;

const int Z = 3 * (int)1e5 + 111;
const int INF = (int)1e9 + 111;
const long long MODF = 1000000007;

long long CC[1111][22];

int main() {
    CC[0][0] = 1;
    for (int n = 1; n <= 1100; ++n) {
    	CC[n][0] = CC[n][n] = 1;
    	for (int k = 1; k < 20; ++k) {
   		    CC[n][k] = ((!n ? 0 : CC[n - 1][k - 1]) + (!n ? 0 : CC[n - 1][k])) % MODF;
        }
    }
    int n, m;
    cin >> n >> m;
    m -= 1;
    long long ans = 0;
    for (int a = 1; a <= n; ++a) {
        for (int b = a; b <= n; ++b) {
            int N1 = a;
            int N2 = n - b + 1;
            ans = (ans + CC[N1 + m - 1][m] * CC[N2 + m - 1][m] % MODF) % MODF;
        }
    }
    cout << ans;

    return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>

#define ft first
#define sd second
#define pb push_back
#define pf push_front
#define mk make_pair
#define all(c) (c).begin(), (c).end()
#define SWS ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define rfile freopen("input.txt", "r", stdin)
#define wfile freopen("output.txt", "w", stdout)
#define files rfile; wfile
#define DEBUG_VAR(x) #x << " = " << x << ";"
#define DEBUG 1

typedef long long ll;
typedef unsigned long long ull;

using namespace std;

const int Z = 3 * (int)1e5 + 111;
const int INF = (int)1e9 + 111;
const int MODF = (int)1e9 + 7;

long long C[1111][22];

int main() {
    for (int n = 0; n <= 1100; ++n) {
    	C[n][0] = C[n][n] = 1;
    	for (int k = 1; k < 20; ++k) {
    		C[n][k] = (C[n-1][k-1] + C[n-1][k]) % MODF;
        }
    }
    SWS;
    int n, m;
    cin >> n >> m;
    m -= 1;
    size_t ans = 0;
    for (int a = 1; a <= n; ++a) {
        for (int b = a; b <= n; ++b) {
            int N1 = a;
            int N2 = n - b + 1;
            ans = (ans + C[N1 + m - 1][m] * C[N2 + m - 1][m] % MODF) % MODF;
        }
    }
    cout << ans;

    return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>

#define ft first
#define sd second
#define pb push_back
#define pf push_front
#define mk make_pair
#define all(c) (c).begin(), (c).end()
#define SWS ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define rfile freopen("input.txt", "r", stdin)
#define wfile freopen("output.txt", "w", stdout)
#define files rfile; wfile
#define DEBUG_VAR(x) #x << " = " << x << ";"
#define DEBUG 1

typedef long long ll;
typedef unsigned long long ull;

using namespace std;

const int Z = 3 * (int)1e5 + 111;
const int INF = (int)1e9 + 111;
const int MODF = 1000000007;

long long C[1111][22];

int main() {
    for (int n = 0; n <= 1100; ++n) {
    	C[n][0] = C[n][n] = 1;
    	for (int k = 1; k < 20; ++k) {
   		    C[n][k] = ((!n ? 0 : C[n - 1][k - 1]) + (!n ? 0 : C[n - 1][k])) % MODF;
        }
    }
    SWS;
    int n, m;
    cin >> n >> m;
    m -= 1;
    long long ans = 0;
    for (int a = 1; a <= n; ++a) {
        for (int b = a; b <= n; ++b) {
            int N1 = a;
            int N2 = n - b + 1;
            ans = (ans + C[N1 + m - 1][m] * C[N2 + m - 1][m] % MODF) % MODF;
        }
    }
    cout << ans;

    return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>

#define ft first
#define sd second
#define pb push_back
#define pf push_front
#define mk make_pair
#define all(c) (c).begin(), (c).end()
#define SWS ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define rfile freopen("input.txt", "r", stdin)
#define wfile freopen("output.txt", "w", stdout)
#define files rfile; wfile
#define DEBUG_VAR(x) #x << " = " << x << ";"
#define DEBUG 1

typedef long long ll;
typedef unsigned long long ull;

using namespace std;

const int Z = 3 * (int)1e5 + 111;
const int INF = (int)1e9 + 111;
const int MODF = (int)1e9 + 7;

size_t C[1111][22];

int main() {
    for (int n = 0; n <= 1100; ++n) {
    	C[n][0] = C[n][n] = 1;
    	for (int k = 1; k < 20; ++k) {
    		C[n][k] = ((!n ? 0 : C[n-1][k-1]) + C[n-1][k]) % MODF;
        }
    }
    SWS;
    int n, m;
    cin >> n >> m;
    m -= 1;
    size_t ans = 0;
    for (int a = 1; a <= n; ++a) {
        for (int b = a; b <= n; ++b) {
            int N1 = a;
            int N2 = n - b + 1;
            ans = (ans + C[N1 + m - 1][m] * C[N2 + m - 1][m] % MODF) % MODF;
        }
    }
    cout << ans;

    return 0;
}