Greg has a pad. The pad's screen is an n × m rectangle, each cell can be either black or white. We'll consider the pad rows to be numbered with integers from 1 to n from top to bottom. Similarly, the pad's columns are numbered with integers from 1 to m from left to right.Greg thinks that the pad's screen displays a cave if the following conditions hold:  There is a segment [l, r] (1 ≤ l ≤ r ≤ n), such that each of the rows l, l + 1, ..., r has exactly two black cells and all other rows have only white cells.  There is a row number t (l ≤ t ≤ r), such that for all pairs of rows with numbers i and j (l ≤ i ≤ j ≤ t) the set of columns between the black cells in row i (with the columns where is these black cells) is the subset of the set of columns between the black cells in row j (with the columns where is these black cells). Similarly, for all pairs of rows with numbers i and j (t ≤ i ≤ j ≤ r) the set of columns between the black cells in row j (with the columns where is these black cells) is the subset of the set of columns between the black cells in row i (with the columns where is these black cells). Greg wondered, how many ways there are to paint a cave on his pad. Two ways can be considered distinct if there is a cell that has distinct colors on the two pictures.Help Greg.

The first line contains two integers n, m — the pad's screen size (1 ≤ n, m ≤ 2000).

In the single line print the remainder after dividing the answer to the problem by 1000000007 (109 + 7).

#include <cstdio>

typedef long long ll;

inline int Get() {
	char ch;
	while ((ch = getchar()) < '0' || ch > '9');
	int Num = ch - '0';
	while ((ch = getchar()) >= '0' && ch <= '9')
		Num = (Num << 3) + (Num << 1) + ch - '0';
	return Num;
}

const int mod = 1e9 + 7;
const int N = 2e3 + 5;

int n, m, f[N][N], pre[N][N], h[N], ans;

int main() {
	n = Get(), m = Get();
	for (int i = 2; i <= m; ++i) f[1][i] = 1;
	for (int i = 1; i <= m; ++i) pre[1][i] = (pre[1][i - 1] + f[1][i]) % mod;
	for (int i = 2; i <= n; ++i) {
		for (int j = 2; j <= m; ++j)
			f[i][j] = (f[i][j - 1] + pre[i - 1][j]) % mod;
		for (int j = 1; j <= m; ++j) pre[i][j] = (pre[i][j - 1] + f[i][j]) % mod;
	}

	for (int k = 2; k <= m; ++k) {
		for (int i = 1; i <= n; ++i) h[i] = (h[i - 1] + f[i][k]) % mod;
		int res = 0;
		for (int i = 1; i <= n; ++i) {
			(res += f[i][k] - f[i - 1][k] + mod) %= mod;
			(ans += (ll)res * h[n - i + 1] % mod * (m - k + 1) % mod) %= mod;
		}
	}
	printf("%d\n", ans);
}

#include<bits/stdc++.h>

#define x first

#define y second

#define eps 1e-8

#define pb push_back

#define inf 0x3f3f3f3f

#define mod 1000000007

#define INF 0x3f3f3f3f3f3f3f3fLL

#define bit(x, y) (((x)>>(y))&1)

#define bctz(x) (__builtin_ctz(x))

#define bclz(x) (__builtin_clz(x))

#define bclzl(x) (__builtin_clzll(x))

#define bctzl(x) (__builtin_ctzll(x))

#define bpt(x) (__builtin_popcount(x))

#define bptl(x) (__builtin_popcountll(x))

#define PQ priority_queue<pii, vector<pii>, greater<pii> >

using namespace std;

typedef double DO;

typedef long long INT;

typedef pair<int, int> pii;

typedef pair<pii, int> pi3;

typedef vector<int> VI;

template<typename T, typename U> inline void smin(T &a, const U &b) {if(a>b) a=b;}

template<typename T, typename U> inline void smax(T &a, const U &b) {if(a<b) a=b;}

template <class T> inline void gn(T &x) {char c, sg=0; while(c=getchar(), (c>'9' || c<'0') && c!='-'); for((c=='-' ? sg=1, c=getchar() : 0), x=0; c>='0' && c<='9'; c=getchar()) x=(x<<1)+(x<<3)+c-'0'; if(sg) x=-x;}

template <class T1, class T2> inline void gn(T1 &x1, T2 &x2) {gn(x1), gn(x2);}

template <class T1, class T2, class T3> inline void gn(T1 &x1, T2 &x2, T3 &x3) {gn(x1, x2), gn(x3);}

template <class T> inline void print(T x) {if(x<0) {putchar('-'); return print(-x);} if(x<10) {putchar('0'+x); return ;} print(x/10); putchar(x%10+'0');}

template <class T> inline void println(T x) {print(x); putchar('\n');}

template <class T> inline void printsp(T x) {print(x); putchar(' ');}

template <class T1, class T2> inline void print(T1 x1, T2 x2) {printsp(x1), println(x2);}

template <class T1, class T2, class T3> inline void print(T1 x1, T2 x2, T3 x3) {printsp(x1), printsp(x2), println(x3);}

int power(int a, int b, int m, int ans=1) {

	for(; b; b>>=1, a=(INT)a*a%m) if(b&1) ans=(INT)ans*a%m;

	return ans;

}

#define NN 2010

int n, m, ans;

int dp[NN][NN], sum[NN][NN], sum2[NN][NN];

int main() {

#ifndef	ONLINE_JUDGE

	freopen("in.in", "r", stdin);

	freopen("out.out", "w", stdout);

#endif

	gn(n, m);

	for(int i=1; i<=n; i++) {

		for(int j=2; j<=m; j++) {

			dp[i][j]=(1+(INT)j*sum[i-1][j]%mod-sum2[i-1][j]+mod)%mod;

			sum[i][j]=sum[i][j-1]+dp[i][j];

			if(sum[i][j]>=mod) sum[i][j]-=mod;

			sum2[i][j]=sum2[i][j-1]+(INT)dp[i][j]*(j-1)%mod;

			if(sum2[i][j]>=mod) sum2[i][j]-=mod;

		}

	}

	for(int i=1; i<=n; i++) {

		for(int j=2; j<=m; j++) {

			int mul=(dp[i][j]-dp[i-1][j]+mod)%mod;

			ans+=(INT)(m-j+1)*mul%mod*dp[n-i+1][j]%mod;

			if(ans>=mod) ans-=mod;

		}

	}

	println(ans);

}

#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;
#define int long long

typedef tree<pair<int, int>, null_type, less<pair<int, int>>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define fs first
#define sc second
#define MP make_pair
#define pb push_back
#define fastio ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define sz(x) (int)x.size()
#define sqr(x) ((x) * (x))

const int MOD = 1e9 + 7;
const int N = 2222;
int f[N][N], pref[N][N], pref2[N][N];

int add(int a, int b) {
    a += b;
    if (a >= MOD)
        a -= MOD;
    if (a < 0)
        a += MOD;
    return a;
}

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

signed main() {
    fastio;

    int n, m;
    cin >> n >> m;
    if (m == 1) {
        cout << "0\n";
        return 0;
    }
    for (int i = 2; i <= m; i++) {
        f[1][i] = 1;
        pref[1][i] = i - 1;
    }
    for (int i = 2; i <= n; i++) {
        f[i][1] = 1;
        for (int j = 2; j <= m; j++) {
            f[i][j] = add(f[i][j - 1], pref[i - 1][j]);
            pref[i][j] = add(f[i][j], pref[i][j - 1]);
        }
    }

    int ans = 0;
    for (int len = 2; len <= m; len++) {
        int cnt = m - len + 1;
        for (int i = 0; i < n; i++) {
            ans = add(ans, mul(cnt, mul(add(f[i + 1][len], -f[i][len]), f[n - i][len])));
        }
    }
    cout << ans << '\n';
}

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <cmath>
#include <cstring>
#include <string>
#include <iostream>
#include <complex>
#include <sstream>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
typedef vector<int> VI;
typedef pair<int,int> PII;

#define REP(i,n) for(int i=0;i<(n);++i)
#define SIZE(c) ((int)((c).size()))
#define FOR(i,a,b) for (int i=(a); i<(b); ++i)
#define FOREACH(i,x) for (__typeof((x).begin()) i=(x).begin(); i!=(x).end(); ++i)
#define FORD(i,a,b) for (int i=(a)-1; i>=(b); --i)
#define ALL(v) (v).begin(), (v).end()

#define pb push_back
#define mp make_pair
#define st first
#define nd second

#define V(a,b,c) (100 * a + 2 * b + c)

int MOD = 1000000007;
const int MAXN = 2005;

LL DP[MAXN][MAXN], DP0[MAXN][MAXN];

int main() {
    int N,M;
    scanf("%d%d",&N,&M);

    if (M == 1) {
        printf("0\n");
        return 0;
    }

    REP(i,M)DP[0][i] = 1;
    FOR(i,1,N+1) {
        DP0[i-1][0] = DP[i-1][0];
        FOR(j,1,M+5) DP0[i-1][j] = (DP[i-1][j] + DP0[i-1][j-1]) % MOD;

        DP[i][0] = i + 1;
        FOR(j,1,M+5) DP[i][j] = (DP[i][j-1] + DP0[i-1][j]) % MOD;
    }

    LL result = 0;
    REP(t,N) {
        REP(w,M-1) {
            LL tmp0 = (M-1 - w) * DP[t][w] % MOD;
            LL tmp1 = DP[N-1-t][w];
            if (N-1-t != 0) tmp1 -= DP[N-1-t-1][w];
            result += tmp0 * tmp1 % MOD;
        }
    }

    result %= MOD;
    result += MOD;
    result %= MOD;

    printf("%d\n", (int)result);
}

#include <bits/stdc++.h>

using namespace std;

const int MOD = 1000000007;
const int N = 2010;

int n,m,f[N][N],ans;

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,t,s;i<=n;i++){
		t=0,s=1;
		for(int j=2;j<=m;j++) t=(t+f[i-1][j])%MOD,f[i][j]=s=(s+t)%MOD;
	}
	for(int i=1;i<=n;i++)
		for(int j=2;j<=m;j++)
			ans=(ans+1ll*(m-j+1)*(f[i][j]-f[i-1][j])%MOD*f[n-i+1][j])%MOD;
	printf("%d\n",(ans+MOD)%MOD);
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=2001,mod=1e9+7;
LL a[maxn][maxn],b[maxn][maxn];
//a[i][j]:第i行两个黑格相距离为j的上方不下降总数
//b[i][j]:反之
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=2;i<=m;i++)
        a[1][i]=1;
    for(int i=2;i<=n;i++)
    {
        for(int j=2;j<=m;j++)
            a[i][j]=(a[i][j-1]+a[i-1][j])%mod;
        for(int j=2;j<=m;j++)
            a[i][j]=(a[i][j]+a[i][j-1])%mod;
        for(int j=2;j<=m;j++)
            a[i][j]=(a[i][j]+1)%mod;
    }
    for(int i=2;i<=m;i++) b[n][i]=1;
    for(int i=n-1;i>=1;i--)
    {
        for(int j=2;j<=m;j++)
            b[i][j]=(b[i][j-1]+a[n-i][j])%mod;
        for(int j=2;j<=m;j++)
            b[i][j]=(b[i][j]+b[i][j-1])%mod;
        for(int j=2;j<=m;j++)
            b[i][j]=(b[i][j]-a[n-i][j]+1)%mod;
    }
    LL ans=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            ans=(ans+((a[i][j]*b[i][j])%mod*(m-j+1))%mod)%mod;
    printf("%I64d\n",ans);
}

//In the name of Allah
//
//
//////////////////////
// Program:
// Written By Alireza Farhadi (LGM)
//////////////////////
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cctype>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <utility>
#include <vector>
#include <bitset>
#include <deque>
#include <iomanip>
#include <complex>
#include <fstream>
#include <sstream>
#include <map>
//#include <climits>
//#include <list>

using namespace std;

#if ( _WIN32 || __WIN32__ )
    #define LLD "%I64d"
#else
    #define LLD "%lld"
#endif

#define show(x) cerr<<((#x))<<" = "<<((x))<<" "<<endl
#define bit(a,b) (((a)>>(b))&1)
#define gcd __gcd
#define endl '\n'
#define bcnt(x) ((__builtin_popcount(x)))
#define sz(x) ((int((x).size())))
#define sqr(x) ((((x))*((x))))
#define fx(x) fixed<<setprecision(x)
#define fl endl<<flush

template<class T> inline void smn(T &a,const T &b){if(b<a) a=b;}
template<class T> inline void smx(T &a,const T &b){if(b>a) a=b;}
template<class T> inline T _rev(const T & a){T _=a; reverse(_.begin(),_.end()); return _;}

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pie;
typedef pie pii;
typedef complex<double> point;

const double eps=1e-8;
const ld leps=1e-14;
const int MN=2000+100;
const int MOD=1000*1000*1000+7;
int d[MN][MN];
int sum[MN][MN];
int n,m;
int fll(int a,int b)
{
	int & res=d[a][b];
	if (res!=-1) return res;
	res=0;
	if (b==0) return res=1;
	if (a<=1) return res=0;
	res=fll(a,b-1);
	res=(ll(res)+2LL*fll(a-1,b)-fll(a-2,b))%MOD;
	if (res<0) res+=MOD;
	return res;
}
int main()
{
	ios_base::sync_with_stdio(false);
	cin>>n>>m;
	memset(d,-1,sizeof(d));
	for (int i=0;i<=n;i++)
		for (int j=0;j<=m;j++)
		{
			if (i==0)
				sum[j][i]=fll(j,i);
			else
				sum[j][i]=(sum[j][i-1]+fll(j,i))%MOD;
		}
	ll res=0;
//	show(fll(2,1));
//	show(fll(3,0));
	for (int i=0;i<n;i++)
		for (int j=2;j<=m;j++)
		{
			ll temp=(m-j+1);
			temp=(ll(temp)*sum[j][i])%MOD;
			ll t=(2*ll(sum[j-1][n-i-1])-sum[j-2][n-i-1])%MOD;
			if (t<0) t+=MOD;
			temp*=t;
			res=res+temp;
			res%=MOD;
		}
	cout<<res<<endl;
	return 0;
}

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define mo 1000000007
using namespace std;
int i,j,k,l,n,m,f[2100][2100],g[2100][2100],ans,t;
int main(){
	scanf("%d%d",&n,&m);
	for(i=1;i<=n+1;++i){
		for(t=0,j=2;j<=m;++j)t=(t+f[i-1][j])%mo,f[i][j]=(f[i][j-1]+t)%mo;
		for(j=2;j<=m;++j)f[i][j]++;
	}
	for(i=1;i<=n;++i)
		for(j=2;j<=m;++j)ans=((long long)f[i][j]*(f[n-i+1][j]-f[n-i][j])%mo*(m-j+1)+ans)%mo;
	printf("%d\n",(ans+mo)%mo);
}

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long LL;
const int N=2001;
const LL mod=1e9+7;
LL up[N][N],down[N][N],he[N];
int main() {
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=2;i<=m;i++) up[1][i]=1;
	for(int i=2;i<=n;i++) {
		for(int j=2;j<=m;j++) up[i][j]=(up[i][j-1]+up[i-1][j])%mod;
		for(int j=2;j<=m;j++) up[i][j]=(up[i][j]+up[i][j-1])%mod;
		for(int j=2;j<=m;j++) up[i][j]=(up[i][j]+1)%mod;
	}
	for(int i=2;i<=m;i++) down[n][i]=1;
	for(int i=n-1;i>=1;i--) {
		for(int j=2;j<=m;j++) down[i][j]=(down[i][j-1]+up[n-i][j])%mod;
		for(int j=2;j<=m;j++) down[i][j]=(down[i][j]+down[i][j-1])%mod;
		for(int j=2;j<=m;j++) down[i][j]=(down[i][j]-up[n-i][j]+1)%mod;
	}
	LL ans=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) ans=(ans+((up[i][j]*down[i][j])%mod*(m-j+1))%mod)%mod;
	printf("%I64d\n",ans);
}

/*
 * Package: StandardCodeLibrary.Core
 * */
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <utility>
#include <vector>
#include <list>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <numeric>
#include <bitset>
#include <complex>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <climits>
#if __GNUC__>=4 and __GNUC_MINOR__>=6
#include <ext/rope>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/tag_and_trait.hpp>
#endif
#ifdef  __GXX_EXPERIMENTAL_CXX0X__
#define typeof decltype
#endif
using namespace std;

#define lp for(;;)
#define repf(i,a,b) for (int i=(a);i<(b);++i)
#define rep(i,n) repf(i,0,n)
#define ft(i,a,b) for (int i=(a);i<=(b);++i)
#define fdt(i,a,b) for (int i=(a);i>=(b);--i)
#define feach(e,s) for (typeof((s).begin()) e=(s).begin();e!=(s).end();++e)
#define fsubset(subset,set) for (int subset=(set)&((set)-1);subset;subset=(subset-1)&(set))
#define forin(i,charset) for (cstr i=(charset);*i;i++)
#define whl while
#define rtn return
#define fl(x,y) memset((x),char(y),sizeof(x))
#define clr(x) fl(x,char(0))
#define cpy(x,y) memcpy(x,y,sizeof(x))
#define pb push_back
#define mp make_pair
#define ins insert
#define ers erase
#define lb lower_bound
#define ub upper_bound
#define rnk order_of_key
#define sel find_by_order
#define x first
#define y second
#define sz(x) (int((x).size()))
#define all(x) (x).begin(),(x).end()
#define srt(x) sort(all(x))
#define uniq(x) srt(x),(x).erase(unique(all(x)),(x).end())
#define rev(x) reverse(all(x))
#define vec vector
#define pr pair
#define que queue
#define prq priority_queue
#define itr iterator
#define sf scanf
#define pf printf
#define pdb(prcs,x) (cout<<setprecision(prcs)<<fixed<<(sgn(x)?(x):0))
#ifdef DEBUG
#define prt(x) cerr<<#x"="<<(x)<<endl
#define asrtWA(s) do if(!(s))do{cerr<<"assert("#s")"<<endl;}whl(0);whl(0)
#define asrtTLE(s) do if(!(s))do{cerr<<"assert("#s")"<<endl;}whl(0);whl(0)
#define asrtMLE(s) do if(!(s))do{cerr<<"assert("#s")"<<endl;}whl(0);whl(0)
#define asrtOLE(s) do if(!(s))do{cerr<<"assert("#s")"<<endl;}whl(0);whl(0)
#define asrtRE(s) do if(!(s))do{cerr<<"assert("#s")"<<endl;}whl(0);whl(0)
#define runtime() cerr<<"Used: "<<db(clock())/CLOCKS_PER_SEC<<"s"<<endl
#define input(in) do{}whl(0)
#define output(out) do{}whl(0)
#else
#define endl (char('\n'))
#define prt(x) (cerr)
#define asrtWA(s) do if(!(s))exit(0);whl(0)
#define asrtTLE(s) do if(!(s))whl(1);whl(0)
#define asrtMLE(s) do if(!(s))whl(new int);whl(0)
#define asrtOLE(s) do if(!(s))whl(1)puts("OLE");whl(0)
#define asrtRE(s) do if(!(s))*(int*)0=0;whl(0)
#define runtime() (cerr)
#define input(in) freopen(in,"r",stdin)
#define output(out) freopen(out,"w",stdout)
#endif

typedef long long int lli;
typedef double db;
typedef const char* cstr;
typedef string str;
typedef vec<int> vi;
typedef vec<vi> vvi;
typedef vec<bool> vb;
typedef vec<vb> vvb;
typedef vec<str> vs;
typedef pr<int,int> pii;
typedef pr<lli,lli> pll;
typedef pr<db,db> pdd;
typedef map<int,int> mii;
typedef map<str,int> msi;
typedef map<char,int> mci;
typedef set<int> si;
typedef set<str> ss;
typedef que<int> qi;
typedef vec<pii> vpii;
typedef vec<pdd> vpdd;
#if __GNUC__>=4 and __GNUC_MINOR__>=6
using __gnu_cxx::rope;
#endif
#if __GNUC__>=4 and __GNUC_MINOR__>=7
template<typename key,typename value>class ext_map:public __gnu_pbds::tree<key,value,less<key>,__gnu_pbds::rb_tree_tag,__gnu_pbds::tree_order_statistics_node_update>{};
template<typename key>class ext_set:public __gnu_pbds::tree<key,__gnu_pbds::null_type,less<key>,__gnu_pbds::rb_tree_tag,__gnu_pbds::tree_order_statistics_node_update>{};
#elif __GNUC__>=4 and __GNUC_MINOR__>=6
template<typename key,typename value>class ext_map:public __gnu_pbds::tree<key,value,less<key>,__gnu_pbds::rb_tree_tag,__gnu_pbds::tree_order_statistics_node_update>{};
template<typename key>class ext_set:public __gnu_pbds::tree<key,__gnu_pbds::null_mapped_type,less<key>,__gnu_pbds::rb_tree_tag,__gnu_pbds::tree_order_statistics_node_update>{};
#endif

int oo=(~0u)>>1;
lli ooll=(~0ull)>>1;
db inf=1e+10;
db eps=1e-10;
db gam=0.5772156649015328606;
db pi=acos(-1.0);
int dx[]={1,0,-1,0,1,-1,-1,1,0};
int dy[]={0,1,0,-1,1,1,-1,-1,0};
int MOD=1000000007;

template<typename type>inline bool cmax(type& a,const type& b){rtn a<b?a=b,true:false;}
template<typename type>inline bool cmin(type& a,const type& b){rtn b<a?a=b,true:false;}
template<typename type>inline type sqr(const type& x){rtn x*x;}
inline int sgn(const db& x){rtn (x>+eps)-(x<-eps);}
inline int dbcmp(const db& a,const db& b){rtn sgn(a-b);}
template<typename istream,typename first_type,typename second_type>inline istream& operator>>(istream& cin,pr<first_type,second_type>& x){rtn cin>>x.x>>x.y;}
template<typename ostream,typename first_type,typename second_type>inline ostream& operator<<(ostream& cout,const pr<first_type,second_type>& x){rtn cout<<x.x<<" "<<x.y;}
template<typename istream,typename type>inline istream& operator>>(istream& cin,vec<type>& x){rep(i,sz(x))cin>>x[i];rtn cin;}
template<typename ostream,typename type>inline ostream& operator<<(ostream& cout,vec<type>& x){rep(i,sz(x))cout<<x[i]<<(i+1==sz(x)?"":" ");rtn cout;}
template<typename type>inline pr<type,type> operator-(const pr<type,type>& x){rtn mp(-x.x,-x.y);}
template<typename type>inline pr<type,type> operator+(const pr<type,type>& a,const pr<type,type>& b){rtn mp(a.x+b.x,a.y+b.y);}
template<typename type>inline pr<type,type> operator-(const pr<type,type>& a,const pr<type,type>& b){rtn mp(a.x-b.x,a.y-b.y);}
template<typename type>inline pr<type,type> operator*(const pr<type,type>& a,const type& b){rtn mp(a.x*b,a.y*b);}
template<typename type>inline pr<type,type> operator/(const pr<type,type>& a,const type& b){rtn mp(a.x/b,a.y/b);}
template<typename type>inline pr<type,type>& operator-=(pr<type,type>& a,const pr<type,type>& b){rtn a=a-b;}
template<typename type>inline pr<type,type>& operator+=(pr<type,type>& a,const pr<type,type>& b){rtn a=a+b;}
template<typename type>inline pr<type,type>& operator*=(pr<type,type>& a,const type& b){rtn a=a*b;}
template<typename type>inline pr<type,type>& operator/=(pr<type,type>& a,const type& b){rtn a=a/b;}
template<typename type>inline type cross(const pr<type,type>& a,const pr<type,type>& b){rtn a.x*b.y-a.y*b.x;}
template<typename type>inline type dot(const pr<type,type>& a,const pr<type,type>& b){rtn a.x*b.x+a.y*b.y;}
template<typename type>inline type gcd(type a,type b){if(b)whl((a%=b)&&(b%=a));rtn a+b;}
template<typename type>inline type lcm(type a,type b){rtn a*b/gcd(a,b);}
template<typename type>inline void bit_inc(vec<type>& st,int x,type inc){whl(x<sz(st))st[x]+=inc,x|=x+1;}
template<typename type>inline type bit_sum(const vec<type>& st,int x){type s=0;whl(x>=0)s+=st[x],x=(x&(x+1))-1;rtn s;}
template<typename type>inline type bit_kth(const vec<type>& st,int k){int x=0,y=0,z=0;whl((1<<(++y))<=sz(st));fdt(i,y-1,0){if((x+=1<<i)>sz(st)||z+st[x-1]>k)x-=1<<i;else z+=st[x-1];}rtn x;}
inline void make_set(vi& st){rep(i,sz(st))st[i]=i;}
inline int find_set(vi& st,int x){int y=x,z;whl(y!=st[y])y=st[y];whl(x!=st[x])z=st[x],st[x]=y,x=z;rtn y;}
inline bool union_set(vi& st,int a,int b){a=find_set(st,a),b=find_set(st,b);rtn a!=b?st[a]=b,true:false;}
template<typename type>inline void merge(type& a,type& b){if(sz(a)<sz(b))swap(a,b);whl(sz(b))a.ins(*b.begin()),b.ers(b.begin());}

struct Initializer{Initializer(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);}~Initializer(){runtime();}}initializer;

lli f[2003][2003];
lli g[2003][2003];

int main()
{
	int n,m;
	cin>>n>>m;
	ft(i,1,n)
	{
		lli sum=0;
		ft(j,2,m)
		{
			f[i][j]=g[i-1][j]+1;
			f[i][j]%=MOD;
			sum+=f[i][j];
			sum%=MOD;
			g[i][j]=g[i][j-1]+sum;
			g[i][j]%=MOD;
		}
//		ft(j,2,m)
//		{
//			ft(k,2,j)
//				g[i][j]+=f[i][k]*(j-k+1);
//				g[i][j]%=MOD;
//			cout<<f[i][j]<<" "<<g[i][j]<<" "<<i<<","<<j<<endl;
//		}
	}
	lli ans=0;
	ft(i,1,n) ft(j,2,m)
	{
		ans+=(f[i][j]*(g[n-i][j]-f[n-i][j]+1)%MOD)*(m-j+1);
		ans%=MOD;
	}
	if (ans<0) ans+=MOD;
	cout<<ans<<endl;
}

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int SIZEN=2010;
const LL MOD=1000000007;
LL realmod(LL x){
	x%=MOD;
	if(x<0) x+=MOD;
	return x;
}
int N,M;
LL R[SIZEN][SIZEN],T[SIZEN][SIZEN];;
LL S[SIZEN],MS[SIZEN];
void calc_sum(int i){
	S[0]=MS[0]=0;
	for(int j=1;j<=M;j++){
		S[j]=realmod(S[j-1]+R[i][j]);
		MS[j]=realmod(MS[j-1]+R[i][j]*j);
	}
}
LL get(LL m){
	LL sum=realmod(S[m]*(m+1));
	sum-=realmod(MS[m]);
	return realmod(sum);
}
void DP(void){
	for(int i=2;i<=M;i++){
		R[1][i]=1;
		T[1][i]=1;
	}
	calc_sum(1);
	for(int i=2;i<=N;i++){
		for(int j=2;j<=M;j++){
			R[i][j]=get(j);
			T[i][j]=realmod(R[i][j]-(S[j]-S[j-1]));
		}
		calc_sum(i);
		for(int j=2;j<=M;j++){
			R[i][j]=realmod(R[i][j]+R[i-1][j]);
			T[i][j]=realmod(T[i][j]+T[i-1][j]);
		}
	}
}
void work(void){
	LL ans=0;
	for(int i=1;i<=N;i++){
		for(int j=2;j<=M;j++){
			LL t=realmod(R[i][j]*T[N+1-i][j]);
			t=realmod(t*(M+1-j));
			ans=realmod(ans+t);
		}
	}
	printf("%I64d\n",ans);
}
int main(){
	//freopen("t1.in","r",stdin);
	scanf("%d%d",&N,&M);
	DP();
	work();
	return 0;
}

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

namespace TYC
{
	typedef long long ll;
	const ll p=1000000007;
	const int N=2010;
	int n,m;
	ll ans,dp[N][N],sum[N][N],sumk[N][N];

	inline void Mod(ll &x) {x=(x>=p?x-p:x);}

	void work()
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=m;i++)
		{
			dp[1][i]=1;
			if(i!=1)
			{
				sum[1][i]=sum[1][i-1]+1;
				sumk[1][i]=sumk[1][i-1]+i;
			}
		}
		for(int i=2;i<=n;i++)
		{
			dp[i][1]=1;
			for(int j=2;j<=m;j++)
			{
				Mod(dp[i][j]=(sum[i-1][j]*(j+1)%p-sumk[i-1][j]+1+p));
				Mod(sum[i][j]=sum[i][j-1]+dp[i][j]);
				Mod(sumk[i][j]=sumk[i][j-1]+dp[i][j]*j%p);
			}
		}
		for(int i=1;i<=n;i++)
			for(int j=2;j<=m;j++)
				Mod(ans+=(dp[i][j]-dp[i-1][j]+p)*dp[n-i+1][j]%p*(m-j+1)%p);
		printf("%lld\n",ans);
	}
}

int main()
{
	TYC::work();
	return 0;
}

#include <bits/stdc++.h>

using namespace std;

#define forn(i, x, n) for(int i = int(x); i <= int(n); ++i)
#define for1(i, n, x) for(int i = int(n); i >= int(x); --i)
#define file ""
#define pb push_back
#define x first
#define y second
#define _bits __builtin_popcountll

typedef long long ll;
typedef double ld;
typedef pair <int, int> PII;

const int N = 2e3 + 10;
const int INF = 1e9 + 9;
const int B = 1e9 + 7;

int n, m;
ll d[N][N], s[N][N], p[N][N], ps[N][N];

int main() {
#ifdef machine42
	freopen(file"in", "r", stdin);
	freopen(file"out", "w", stdout);
#endif
	ios_base :: sync_with_stdio (0);
	cin.tie(0);

	cin >> n >> m;

	forn(len, 2, m) {
		d[1][len] = 1;
		s[1][len] = len - 1;
		p[1][len] = 1;
	}
	forn(i, 2, n) {
		forn(len, 2, m) {
			d[i][len] = (d[i][len - 1] + s[i - 1][len - 1] + d[i - 1][len]) % B;
			s[i][len] = (s[i][len - 1] + d[i][len]) % B;
			p[i][len] = (p[i - 1][len] + d[i][len]) % B;
		}
	}

	forn(i, 1, n)
		forn(len, 2, m)
			ps[i][len] = (ps[i][len - 1] + p[i][len]) % B;

	ll ans = 0;
	forn(k, 1, n) {
	    ll bot = 0;
		forn(len, 2, m) {
			ll top = p[k][len] * (m - len + 1) % B;
			bot = (bot + ps[n - k][len - 2] + 2 * p[n - k][len - 1]) % B;
			ans = (ans + top * (bot + 1) % B) % B;
		}
	}
	cout << ans << "\n";

	return 0;
}

#include <iostream>
#define MAXN 2005
#define MOD 1000000007

using namespace std;

int n, m;
long long res, c[MAXN][MAXN];

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

  long long p, q, s;
  for (int i = 1; i <= n; i++)
  {
    p = 1, q = 0;
    for (int j = 2; j <= m; j++)
    {
      q = (q + c[i - 1][j]) % MOD;
      p = (p + q) % MOD;
      c[i][j] = p;
    }
  }

  res = 0;
  for (int i = 1; i < n; i++)
  {
    p = 1; q = 0;
    for (int j = 2; j <= m; j++)
    {
      s = m - j + 1;
      p = (p + q) % MOD;
      q = (q + c[n - i][j]) % MOD;
      res = (res + s * (c[i][j] * p % MOD)) % MOD;
      p = (p + c[n - i][j]) % MOD;
    }
  }
  for (int j = 2; j <= m; j++)
  {
    s = m - j + 1;
    res = (res + s * c[n][j]) % MOD;
  }

  cout << res;

//  system("pause");
}

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define Fast_IO ios::sync_with_stdio(false);
#define fir first
#define sec second
#define mod 1000000007
#define INF 0x3fffffff
#define ll long long
inline int read()
{
	char ch=getchar(); int nega=1; while(!isdigit(ch)) {if(ch=='-') nega=-1; ch=getchar();}
	int ans=0; while(isdigit(ch)) {ans=ans*10+ch-48;ch=getchar();}
	if(nega==-1) return -ans;
	return ans;
}
typedef pair<int,int> pii;
int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int sub(int x,int y){return x-y<0?x-y+mod:x-y;}
int mul(int x,int y){return 1LL*x*y%mod;}
#define N 2005
int f[N][N],sum[N][N];
signed main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=m;i++) f[1][i]=1,sum[1][i]=i-1;
	for(int i=2;i<=n;i++)
	{
		f[i][1]=1;
		for(int j=2;j<=m;j++) f[i][j]=add(f[i][j-1],sum[i-1][j]);
		sum[i][2]=f[i][2];
		for(int j=3;j<=m;j++) sum[i][j]=add(sum[i][j-1],f[i][j]);
	}
	// for(int i=1;i<=n;i++)
	// {
		// for(int j=1;j<=m;j++) printf("%d ",f[i][j]);
		// cout<<"\n";
	// }
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=2;j<=m;j++)
		{
			int R=mul(sub(f[i][j],f[i-1][j]),f[n-i+1][j]);
			ans=add(ans,mul(R,m-j+1));
		}
	}
	cout<<ans<<endl;
	return 0;
}

//hello

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

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double ld;
typedef pair<int,int> pii;
typedef pair<ld,ld> pdd;
typedef pair<ll,ll> pll;

#define X first
#define Y second

const int MaxN=2010;
const int MOD=1000000007;

int n,m;
ll F[MaxN][MaxN],sF[MaxN][MaxN],tF[MaxN][MaxN],a[MaxN][MaxN],b[MaxN][MaxN],c[MaxN][MaxN],d[MaxN][MaxN];
ll ans;

int main()
{
	cin>>n>>m;
	for (int i=1;i<m;++i)
	{
		F[1][i]=1;
		sF[1][i]=(sF[1][i-1]+F[1][i])%MOD;
		tF[1][i]=(tF[1][i-1]+F[1][i]*i)%MOD;
	}
	for (int i=2;i<=n;++i)
		for (int j=1;j<m;++j)
		{
			F[i][j]=((j+1)*sF[i-1][j]-tF[i-1][j])%MOD;
			sF[i][j]=(sF[i][j-1]+F[i][j])%MOD;
			tF[i][j]=(tF[i][j-1]+F[i][j]*j)%MOD;
		}
	for (int i=1;i<=n;++i)
		for (int j=1;j<m;++j)
		{
			a[i][j]=(a[i-1][j]+a[i][j-1]-a[i-1][j-1]+F[i][j])%MOD;
			b[i][j]=(b[i-1][j]+b[i][j-1]-b[i-1][j-1]+F[i][j]*i)%MOD;
			c[i][j]=(c[i-1][j]+c[i][j-1]-c[i-1][j-1]+F[i][j]*j)%MOD;
			d[i][j]=(d[i-1][j]+d[i][j-1]-d[i-1][j-1]+F[i][j]*i*j)%MOD;
		}
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m;++j)
		{
			int ii=n-i,jj=j-1,ki=n-i+1,kj=j+1;
			ans=(ans+(a[ii][jj]*ki*kj-b[ii][jj]*kj-c[ii][jj]*ki+d[ii][jj])%MOD*(F[i][j]*(m-j)%MOD)+F[i][j]*(n-i+1)*(m-j))%MOD;
		}
	cout<<ans<<endl;
	return 0;
}

#include <iostream>
#include <cstdio>

#include <queue>
#include <cstring>

using namespace std;

#define FILE_NAME "io"

const int MAXSIZE = 2001;
const long long BASE = 1000000007;

int n, m;

long long dp[MAXSIZE + 1][MAXSIZE + 1];
long long sum[MAXSIZE + 1][MAXSIZE + 1];

int main()
{
    #ifndef ONLINE_JUDGE
    freopen (FILE_NAME".in", "r", stdin);
    freopen (FILE_NAME".out", "w", stdout);
    #endif // ONLINE_JUDGE

    scanf ("%d%d", &n, &m);

    for (int l = 1; l < m; l++)
        dp[1][l] = 1;

    for (int i = 2; i <= n; i++) {
        long long sum = 0;
        for (int j = 1; j < m; j++) {
            sum += dp[i - 1][j];
            dp[i][j] = (dp[i][j - 1] + sum) % BASE;
        }
    }

    for (int j = 1; j < m; j++)
        for (int t = n - 1; t >= 0; t--)
            sum[n - t][j] = sum[n - t - 1][j] + dp[n - t][j];

    long long ANS = 0;
    for (int t = 1; t <= n; t++) {
        for (int j = 1; j < m; j++) {
            long long count = (sum[n - t + 1][j] * (m - j)) % BASE;
            ANS = (ANS + dp[t][j] * count) % BASE;
        }
    }

    printf ("%I64d", ANS);

    return 0;
}

#include <cstdio>
#include <iostream>
#include <algorithm>
#define N 2000
#define MOD 1000000007
using namespace std;
typedef long long LL;
void add(int &a, LL b) { a += b, a %= MOD; }
int f[N + 5][N + 5], g[N + 5][N + 5];
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	if (m == 1) { puts("0"); return 0; }
	for (int i = 1; i <= n; i++)
		for (int j = 2, s1 = 0, s2 = 0; j <= m; j++) {
			add(s1, s2);
			g[i][j] = s1 + 1;
			add(s1, f[i - 1][j]), add(s2, f[i - 1][j]);
			f[i][j] = s1 + 1;
		}
	int ans = 0;
	for (int i = 1; i <= n; i++)
		for (int j = 2; j <= m; j++)
			add(ans, f[i][j] * 1ll * g[n - i + 1][j] % MOD * (m - j + 1) % MOD);
	printf("%d\n", ans);
	return 0;
}

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

#define ll long long
#define mp make_pair
#define pb push_back

#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#define rep(i, n) for (int i = 0; i < (int)(n); ++ i)

const int mod = 1e9 + 7;
int n, m;
int f[2005][2005];
int c[6005][6005];

int main() {
	scanf("%d %d", &n, &m);
	rep(i, 6005) rep(j, i + 1) c[i][j] = j ? (c[i - 1][j - 1] + c[i - 1][j]) % mod : 1;
	for (int l = 1; l <= n; ++ l) for (int y = 2; y <= m; ++ y) f[l][y] = (c[2 * l + y - 4][y - 2] + f[l - 1][y]) % mod;
	int ans = 0;
	for (int y = 2; y <= m; ++ y) {
		(ans += 1LL * (m - y + 1) % mod * f[n][y] % mod) %= mod;
		for (int t = 2; t <= n; ++ t) (ans += 1LL * (m - y + 1) % mod * f[t][y] % mod * f[n - t + 1][y] % mod) %= mod;
		for (int t = 2; t <= n; ++ t) (ans += mod - 1LL * (m - y + 1) % mod * f[t - 1][y] % mod * f[n - t + 1][y] % mod) %= mod;
	}
	printf("%d\n", ans);
	return 0;
}

#include <bits/stdc++.h>
typedef long long LL;
#define rep(i,n) for(int i = 0;i < n;i ++)

const int N = 2015;
const int mod = 1e9 + 7;
int dp[N][N], f[N][N];
void add(int &x, int val) {
	x += val;
	if(x >= mod)
		x -= mod;
}
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	int ans = 0;
	for(int i = 0; i <= n; i ++)	f[i][1] = 1;
	for(int j = 0; j <= m; j ++)	f[0][j] = 1;
	for(int i = 1; i <= n; i ++) {
		int sum = 0;
		for(int j = 2; j <= m; j ++) {
			add(dp[i][j], f[i - 1][j]);
			add(sum, dp[i][j]);
			add(f[i][j], sum);
			add(f[i][j], f[i][j - 1]);
		}
	}
	for(int i = 1; i <= n; i ++) {
		for(int j = 2; j <= m; j ++) {
			int t = (f[n - i][j] - dp[n - i][j] + mod) % mod;
			t = (LL)t * dp[i][j] % mod * (m - j + 1) % mod;
			add(ans, t);
		}
	}
	printf("%d\n", ans);
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(int i = (int)(a); i <= (int)(b); i++)
#define NFOR(i,a,b) for(int i = (int)(a); i >= (int)(b); --i)
#define endl "\n"
#define mp make_pair
#define X first
#define Y second
#define inf 1e15
#define mod 1000000007
#define pb push_back
#define Case cout<<"Case #"<<++cas<<": ";
#define fastio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define all(v) v.begin(),v.end()
#define sz(x) int(x.size())
// #define lli int
typedef long long int lli;
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<pii> vii;
typedef pair<lli,lli> pll;
typedef vector<lli> vl;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<vl> vvl;

#define pr(...) dbs(#__VA_ARGS__, __VA_ARGS__)
template <class T> void dbs(string str, T t) {cerr << str << " : " << t << "\n";}
template <class T, class... S> void dbs(string str, T t, S... s) {int idx = str.find(','); cerr << str.substr(0, idx) << " : " << t << ","; dbs(str.substr(idx + 1), s...);}
template <class S, class T>ostream& operator <<(ostream& os, const pair<S, T>& p) {return os << "(" << p.first << ", " << p.second << ")";}
template <class T>ostream& operator <<(ostream& os, const vector<T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}
template <class T>ostream& operator <<(ostream& os, const set<T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}
template <class S, class T>ostream& operator <<(ostream& os, const map<S, T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}
template <class T> void prc(T a, T b) {cerr << "["; for (T i = a; i != b; ++i) {if (i != a) cerr << ", "; cerr << *i;} cerr << "]\n";}

const int N = 2010;
const int M = 2010;

ll dp[N + 1][M + 1];

void calc() {
	FOR(j, 1, M) dp[1][j] = 1;
	FOR(i, 2, N) {
		ll cumSum = 0; dp[i][1] = 1;
		FOR(j, 2, M) {
			(cumSum += dp[i - 1][j]) %= mod;
			dp[i][j] = (dp[i][j - 1] + cumSum)%mod;
		}
	}
}

int main() {
	calc();
	int n, m; cin >> n >> m;
	ll answer1 = 0;
	FOR(i, 1, n) {
		FOR(j, 2, m) {
			answer1 = (answer1 + (((m - j + 1)*(dp[i][j] - dp[i - 1][j] + mod))%mod * dp[n - i + 1][j])%mod)%mod;
		}
	}
	cout << answer1 << "\n";
}

#include<cstdio>
#define int long long
using namespace std;
inline int read(){int x=0,f=1,ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}
inline void write(int x){if (x<0) putchar('-'),x=-x; if (x>=10) write(x/10); putchar(x%10+'0');}
inline void writeln(int x){write(x); puts("");}
const int N=2005,mod=1e9+7;
int n,m,dp[N][N],sum,ans;
inline void init(){
	n=read(); m=read();
}
inline void update(int &x,int y){
	x=(x+y)%mod;
}
inline void solve(){
	for (int i=1;i<=m;i++) dp[1][i]=1;
	for (int i=2;i<=n;i++){
		dp[i][1]=1; sum=0;
		for (int j=2;j<=m;j++){
			update(sum,dp[i-1][j]);
			update(dp[i][j],sum+dp[i][j-1]);
		}
	}
	for (int i=1;i<=n;i++){
		for (int j=2;j<=m;j++){ //枚举下面
			update(ans,(dp[i][j]-dp[i-1][j]+mod)%mod*dp[n-i+1][j]%mod*(m-j+1)%mod);
		}
	}
	writeln(ans);
}
signed main(){
	init(); solve();
	return 0;
}

#include<stdio.h>
#include<cmath>
#include<utility>
#include<algorithm>
using namespace std;
//#define TEST
#define llong long long
llong N, M, prime = 1000000007;
llong dp[2005][2005] = {0};
int main()
{
    FILE *INPUT = stdin;
#ifdef TEST
    INPUT = fopen("input.txt", "r");
#endif
    fscanf(INPUT, "%d%d",&N,&M);
    int i1 = 0, i2 = 0, i3 = 0;
    llong val1 = 0, val2 = 0, val3 = 0;
    for( i1 = 1; i1 <= N; ++ i1)
    {
        val1 = 0;
        val2 = 1;
        for( i2 = 2; i2 <= M; ++ i2)
        {
            val1 = (val1 + dp[i1 - 1][i2]) % prime;
            val2 = (val1 + val2) % prime;
            dp[i1][i2] = val2;
        }
    }
    llong caves = 0;
    for( i1 = 2; i1 <= M; ++ i1)
    {
        val1 = 0;
        val2 = 0;
        for( i2 = 1; i2 <= N; ++ i2)
        {
            val1 = dp[i2][i1] - dp[i2 - 1][i1];
            val2 = (val2 + val1 * dp[N - i2 + 1][i1]) % prime;
        }
        val2 = (val2 * (M - i1 + 1)) % prime;
        caves = (caves + val2) % prime;
    }
    printf("%d\n", (prime + caves) % prime);
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define MAXN 2010
#define LL long long
#define MOD 1000000007
int N, M;
LL F[MAXN][MAXN], sum, ans;

int main()
{
	scanf("%d%d", &N, &M);
	for(int i = 1; i <= N; i++)
	{
		sum = F[i - 1][2];
		F[i][2] = sum + 1;
		for(int j = 3; j <= M; j++)
		{
			sum = (sum + F[i - 1][j]) % MOD;
			F[i][j] = (sum + F[i][j - 1]) % MOD;
		}
	}
	ans = 0LL;
	for(int i = 1; i <= N; i++)
		for(int j = 2; j <= M; j++)
			ans = (ans + F[i][j] * (F[N - i + 1][j] - F[N - i][j]) % MOD * (M - j + 1) % MOD) % MOD;
    printf("%I64d\n",ans);
	return 0;
}

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cmath>
#include <iostream>
#include <algorithm>

using namespace std;

const int p = 1000000007;
int n, m, f[2001][2001][2];

int main() {
     //freopen("295d.in", "r", stdin);
     //freopen("295d.out", "w", stdout);
     scanf("%d%d", &n, &m);
     if (m == 1) {
          printf("0\n");
          return 0;
     }
     memset(f, 0, sizeof(f));
     //for (int j = 2; j <= m; j++) f[0][j][0] = 1;
     for (int i = 1; i <= n; i++) {
          int sum = 0, value = 1;
          for (int j = 2; j <= m; j++) {
               value += sum; value %= p;
               f[i][j][0] = value;
               sum += (f[i - 1][j][0] + f[i - 1][j][1]) % p; sum %= p;
               f[i][j][1] = (f[i - 1][j][0] + f[i - 1][j][1]) % p;
               value += (f[i - 1][j][0] + f[i - 1][j][1]) % p; value %= p;
          }
     }
     int ans = 0;
     for (int i = 1; i <= n; i++)
          for (int j = 2; j <= m; j++)
               ans += (1LL * (f[i][j][0] + f[i][j][1]) % p * f[n - i + 1][j][0]) % p * (m - j + 1) % p,
               ans %= p;//,
              // printf("%d %d %d %d\n", i, j, f[i][j][0] + f[i][j][1], f[n - i + 1][j][0]);
     printf("%d\n", ans);
}

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long LL;
const int N=2001;
const LL mod=1e9+7;
LL up[N][N],down[N][N],he[N];
int main() {
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=2;i<=m;i++) up[1][i]=1;
	for(int i=2;i<=n;i++) {
		for(int j=2;j<=m;j++) up[i][j]=(up[i][j-1]+up[i-1][j])%mod;
		for(int j=2;j<=m;j++) up[i][j]=(up[i][j]+up[i][j-1])%mod;
		for(int j=2;j<=m;j++) up[i][j]=(up[i][j]+1)%mod;
	}
	for(int i=2;i<=m;i++) down[n][i]=1;
	for(int i=n-1;i>=1;i--) {
		for(int j=2;j<=m;j++) down[i][j]=(down[i][j-1]+up[n-i][j])%mod;
		for(int j=2;j<=m;j++) down[i][j]=(down[i][j]+down[i][j-1])%mod;
		for(int j=2;j<=m;j++) down[i][j]=(down[i][j]-up[n-i][j]+1)%mod;
	}
	LL ans=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) ans=(ans+((up[i][j]*down[i][j])%mod*(m-j+1))%mod)%mod;
	printf("%I64d\n",ans);
}

#include <cstdio>
#include <vector>
#include <cstring>
#include <functional>
#include <algorithm>
#include <math.h>
#include <bitset>
#include <set>
#include <queue>
#include <iostream>
#include <string>
#include <sstream>
#include <stack>
#include <complex>
#include <numeric>
#include <map>
#include <time.h>
using namespace std;
typedef long double ld;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
typedef pair<ll,int> pli;
typedef pair<ll,ll> pll;
typedef pair<pii,ll> ppl;
typedef pair<ll,pii> plp;
typedef pair<int,pii> pip;
typedef pair<pii,int> ppi;
typedef pair<pii,pii> ppp;
typedef pair<double,int> pdi;
typedef pair<double,pii> pdp;
typedef pair<double,double> pdd;
typedef pair<pdd,double> pd3;
typedef vector<double> vec;
typedef vector<vec> mat;
#define rep(i,n) for (int (i) = 0; (i) < (n); (i)++)
#define repn(i,a,n) for (int (i) = (a); (i) < (n); (i)++)
#define ALL(x) (x).begin(),(x).end()
#define pb push_back
#define SORT(x) sort((x).begin(),(x).end())
#define SORTN(x,n) sort((x),(x)+(n))
#define ERASE(x) (x).erase(unique((x).begin(),(x).end()),(x).end())
#define COUNT(x,c) count((x).begin(),(x).end(),(c))
#define REMOVE(x,c) (x).erase(remove((x).begin(),(x).end(),(c)),(x).end())
#define REVERSE(x) reverse((x).begin(),(x).end())
#define FORIT(it,v) for(__typeof((v).begin()) it=(v).begin();it!=(v).end();it++)
#define LB(x,a) lower_bound((x).begin(),(x).end(),(a))-(x).begin()
#define lb(x,a) lower_bound((x).begin(),(x).end(),(a))
#define LBN(x,a,n) lower_bound((x),(x)+(n),(a))-(x)
#define lbN(x,a,n) lower_bound((x),(x)+(n),(a))
#define UB(x,a) upper_bound((x).begin(),(x).end(),(a))-(x).begin()
#define ub(x,a) upper_bound((x).begin(),(x).end(),(a))
#define BS(x,a) binary_search((x).begin(),(x).end(),(a))
#define BS2(x,n,a) binary_search((x),(x)+(n),(a))
#define NB(x) (((x)&~((x)+((x)&-(x))))/((x)&-(x))>>1)|((x)+((x)&-(x)))
#define NP(x) next_permutation((x).begin(),(x).end())
#define MM(x,p) memset((x),(p),sizeof(x))
#define SQ(x) (x)*(x)
#define SC(c1,c2) strcmp(c1,c2)==0
#define mp make_pair
#define INF (1<<29)
#define INFL (1LL<<61)
#define fi first
#define se second
#define MOD 1000000007
#define EPS 1e-10
#define MIN(x,a) x=min(x,a)
#define MAX(x,a) x=max(x,a)
#define madd(x,a) x=(x+a)%MOD
#define msub(x,a) x=(x+MOD-a)%MOD
#define OUTPUT(x) rep(i,x.size())printf("%d%c",x[i],i+1==x.size()?'\n':' ');

int H,W;
int dp[2015][2015];
int dp2[2015][2015];
int tmp[2015];

void init(int x)
{
    tmp[0]=0;
    repn(i,1,2015)tmp[i]=(tmp[i-1]+dp[x][i])%MOD;
}

int main()
{
    scanf("%d%d",&H,&W);
    repn(i,2,W+1)dp[1][i]=dp2[1][i]=1;
    for(int i=2;i<=H;i++)
    {
        init(i-1);
        int tt=0;
        for(int j=2;j<=W;j++)
        {
            madd(tt,tmp[j]);
            madd(dp[i][j],tt);
            madd(dp[i][j],1);
            madd(dp2[i][j],tt);
            madd(dp2[i][j],1);
            msub(dp2[i][j],dp[i-1][j]);
        }
    }
    int res=0;
    repn(i,1,H+1)repn(j,2,W+1)
    {
        int k=H-i+1;
        madd(res,ll(dp[i][j])*ll(dp2[k][j])%MOD*(W-j+1)%MOD);

    }
    printf("%d\n",res);
}

/* 2013-07-26 09:25:46.498501 */#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <iostream>
using namespace std;

const long long mod = 1000000007;
const int MAXN = 2005;
int n, m;
long long f[MAXN][MAXN], g[MAXN][MAXN];

int main() {

	scanf("%d %d", &n, &m);

	for(int i = 2; i <= m; i++)
		f[1][i] = 1;
	for(int i = 2; i <= n; i++) {
		long long sum = 0, summ = 0;
		for(int j = 2; j <= m; j++) {
			sum = (sum + f[i - 1][j]) % mod;
			summ = (summ + f[i - 1][j] * j % mod) % mod;
			f[i][j] = (-summ + sum * (j + 1) % mod + mod) % mod;
		}
	}
	for(int i = 2; i <= m; i++)
		g[0][i] = 1;
	for(int i = 1; i <= n; i++) {
		long long sum = 0, summ = 0;
		for(int j = 1; j <= m; j++) {
			g[i][j] = (-summ + sum * (j + 1) % mod + mod) % mod;
			sum = (sum + f[i][j]) % mod;
			summ = (summ + f[i][j] * j % mod) % mod;
		}
	}
	long long ans = 0;
	for(int i = 2; i <= m; i++) {
		long long sum1 = 0;
		for(int j = 1; j <= n; j++) {
			sum1 = (sum1 + f[j][i]) % mod;
		}
		long long sum2 = g[0][i], res = 0;
		for(int j = n; j >= 1; j--) {
			res = (res + sum1 * sum2 % mod) % mod;
			sum2 = (sum2 + g[n - j + 1][i]) % mod;
			sum1 = (sum1 - f[j][i] + mod) % mod;
		}
		ans = (ans + res * (m - i + 1) % mod) % mod;
	}
	cout << ans << endl;
	return 0;
}

#include <bits/stdc++.h>

#define si(a) scanf("%d",&a)
#define f first
#define s second
#define mp(a,b) make_pair(a,b)
#define MOD 1000000007
#define MAX 2005

using namespace std;

int mod_plus(int a,int b)
{
    return (a+b)%MOD;
}

int mod_mul(long long a,long long b)
{
    return (a*b)%MOD;
}

int mod_min(int a,int b)
{
    return (a-b+MOD)%MOD;
}

int dp[MAX][MAX],n,m;

void precal(void)
{
    for(int i=1;i<=n;i++){
        int jog=0,ttt=0;
        for(int j=2;j<=m;j++){
            ttt=mod_plus(ttt,dp[i-1][j]);
            jog=mod_plus(jog,ttt);
            dp[i][j]=mod_plus(jog,1);
        }
    }
    return ;
}

int main()
{
    //freopen("input.txt","r",stdin);
    si(n);si(m);
    if(m==1){
        cout<<0<<endl;
        return 0;
    }
    precal();

    int ans=0;
    for(int i=1;i<=n;i++){
        ans=mod_plus(ans,(m-1)*(n-i+1));
        int jog=0,ttt=0;
        for(int j=3;j<=m;j++){
            ttt=mod_plus(ttt,dp[n-i][j-1]);
            jog=mod_plus(jog,ttt);
            jog=mod_plus(jog,dp[n-i][j-1]);
            ans=mod_plus(ans,mod_mul(m-j+1,mod_mul(dp[i][j],mod_plus(jog,1))));
            //cout<<i<<" "<<j<<" "<<ans<<endl;
        }
    }
    cout<<ans<<endl;
    return 0;
}

//Michał Glapa
#include<cstdio>
#include<set>
#include<vector>
#include<algorithm>
#include<queue>
#include<map>
#include<cstdlib>
#include<time.h>
#include<stack>
#include<cmath>
#include<iostream>
#include<cstring>
#include<tr1/unordered_set>
#include<tr1/unordered_map>
using namespace std;
#define FOR(i,j,k) for(int i=j;i<k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define ll long long
#define pii  pair<int, int>
#define vi vector<int >
#define pb push_back
#define mp make_pair
#define make(n) int n; scanf("%d",&n)
#define st first
#define nd second
#define INF 2000000001
#define VAR(i,n) __typeof(n) i = (n)
#define FOREACH(i,c) for(VAR(i,(c).begin());i!=(c).end();i++)
#define FORDEACH(i,c) for( VAR(i,(c).rbegin(),i!=(c).rend();i++)
#define REP(i,n) FOR(i,0,n)
#define ld long double
const long long INFLL = (ll)INF * (ll)INF;
const ld EPS = 10e-9;

#define MAXN 2007
#define int long long

int dp[MAXN][MAXN];
int dp2[MAXN][MAXN];
int MOD = 1000000007;
main()

{
    int n,m;
    scanf("%I64d %I64d",&n,&m);
    //DP
    for(int i=0;i<=m-2;i++)
        dp[i][0]=1;
    for(int h=1;h<n;h++)
    {
        int sum=0;
        int val=0;
        for(int l=0;l<=m-2;l++)
        {
            sum+=dp[l][h-1];
            val+=sum;
            sum%=MOD;
            val%=MOD;
            if(val<0) val+=MOD;
            dp[l][h]=val;

        }
    }
    //DP2
    for(int l=0;l<=m-2;l++)
        dp2[l][0]=dp[l][0];
    for(int h=1;h<n;h++)
    {
        for(int l=0;l<=m-2;l++)
            dp2[l][h] =( dp2[l][h-1]+dp[l][h])%MOD;
    }
    //res
    int res=0;
    for(int i=0;i<n;i++)
    {
        for(int l=0;l<=m-2;l++)
        {
            int tmp=(dp2[l][i]*((dp2[l][n-1-i] - (n-1-i >0 ? dp2[l][n-2-i] : 0))%MOD));
            tmp%=MOD;
            tmp*=m-l-1;
            tmp%=MOD;
            //printf("%d\n",tmp);
            res+=tmp;
            res%=MOD;
        }
    }
    if(res < 0)
        res+=MOD;
    printf("%I64d\n",res);

}

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;

const int maxn = 2107, MOD = 1000000007;

int n, m;
int f[maxn][maxn], g[maxn][maxn];
int t[maxn][maxn];

void solve()
{
    scanf("%d%d", &n, &m);
    if (m == 1) {
        puts("0");
        return;
    }
    --m;
    memset(f, 0, sizeof(f));
    memset(g, 0, sizeof(g));
    for (int i = 1; i <= m; ++i) {
        f[i][0] = 1;
        g[i][0] = i;
    }
    for (int j = 1; j <= n; j++)
    {
        long long sum = 0;
        for (int i = 1; i <= m; i++)
        {
            //f[i][j] = (f[i-1][j-1]+g[i][j-1])%MOD;
            //g[i][j] = (g[i-1][j]+f[i][j])%MOD;

            sum += f[i][j - 1];
            sum %= MOD;
            f[i][j] = sum;
            sum = sum + g[i][j - 1];
            sum %= MOD;
            g[i][j] = g[i - 1][j] + f[i][j];
            g[i][j] %= MOD;

        }
    }

    for (int i = 1; i <= m; ++i) {
        t[i][0] = f[i][0];
        for (int j = 1; j <= n; ++j) {
            if(j) t[i][j] = t[i][j - 1] + f[i][j];
            t[i][j] %= MOD;
        }
    }

    long long ans = 0;
    for (int length = 1; length <= m; ++length)
    {
        for (int i = 1; i <= n; ++i)
        {
            int left = i - 1, right = n - i;
            long long coff = t[length][right];
            if (right > 0)
            {
                coff -= t[length][right - 1];
                coff %= MOD;
            }
            long long tmp = t[length][left] * coff;
            tmp = tmp % MOD * (m - length + 1);
            ans = (ans + tmp) % MOD;
        }
    }

    ans = (ans + MOD) % MOD;
    cout << ans << endl;
}

int main()
{
    solve();
    return 0;
}

#include<bits/stdc++.h>
#define mk make_pair
#define fi first
#define nd second
#define pii pair<int,int>
#define pb push_back
#define sqr(x) ((x)*(x))
using namespace std;
typedef long long ll;
inline ll read() {ll x = 0; char ch = getchar(), w = 1;while(ch < '0' || ch > '9') {if(ch == '-') w = -1;
ch = getchar();}while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}return x * w;}
void write(ll x) {if(x < 0) putchar('-'), x = -x;if(x > 9) write(x / 10);putchar(x % 10 + '0');}
inline void writeln(ll x) {write(x);puts("");}
const int N = 110000;
const ll p = 1e9 + 7;
int n, m;
ll f[2100][2100], ans;

int main() {
	n = read();m = read();
	f[0][0] = 1;
	for(int i = 1; i <= n; ++i) {
		f[i][0] = 1;
		ll sum = 1, res = 0;
		for(int j = 2; j <= m; ++j) {
			res += f[i - 1][j];
			res %= p;
			sum += res;
			sum %= p;
			f[i][j] = sum;
		}
	}
/*	for(int i = 1; i <= n; ++i)
		for(int j = 2; j <= m; ++j)
			for(int k = 1; k <= j; ++k)
				(ans += (f[i][j] - f[i - 1][j])* f[n - i][k]  * (j - k + 1)) %= p;*/
	for(int i = 1; i <= n; ++i)
		for(int j = 2; j <= m; ++j)
			(ans += (f[i][j] - f[i - 1][j] )* f[n - i + 1][j]  % p * (m - j + 1)) %= p;
	ans = (ans + p) % p;
	writeln(ans);
}

#include<bits/stdc++.h>
#define For(i,x,y) for (register int i=(x);i<=(y);i++)
#define Dow(i,x,y) for (register int i=(x);i>=(y);i--)
#define cross(i,k) for (register int i=first[k];i;i=last[i])
using namespace std;
typedef long long ll;
inline ll read(){
    ll x=0;int ch=getchar(),f=1;
    while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
    if (ch=='-'){f=-1;ch=getchar();}
    while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
const int N = 2010, mod = 1e9+7;
int n,m;
int dp[N][N],sum[N][N],Sum[N][N];
inline void init(){
	n=read(),m=read();
	For(i,0,m-2) dp[1][i]=1,sum[1][i]=sum[1][i-1]+1,Sum[1][i]=Sum[1][i-1]+i;
	For(i,2,n)
		For(j,0,m-2){
			dp[i][j]=(1ll*sum[i-1][j]*(j+1)%mod-Sum[i-1][j]+mod)%mod;
			sum[i][j]=(sum[i][j-1]+dp[i][j])%mod,Sum[i][j]=(Sum[i][j-1]+1ll*dp[i][j]*j%mod)%mod;
		}
}
int ans,Ans[N][N];
inline void calc(){
	For(i,1,n) For(j,0,m-2) Ans[i][j]=(Ans[i-1][j]+dp[i][j])%mod;
	For(i,1,n) For(j,0,m-2) ans=(ans+1ll*Ans[i][j]*(m-j-1)%mod*dp[n-i+1][j]%mod)%mod;
	printf("%d\n",ans);
}
int main(){
	init(),calc();
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<queue>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define LL long long
LL n,m;
LL f[2020][2020];
LL s[2020][2020];
const LL mod=1000000007;
int main()
{
    cin>>n>>m;
    for(LL i=2;i<=m;i++)
        f[1][i]=1;
    for(LL i=2;i<=n;i++)
    {
        LL tmp=0,tmp1=0;
        for(LL j=2;j<=m;j++)
        {
            (tmp+=f[i-1][j])%=mod;
            (tmp1+=f[i-1][j]*j)%=mod;
            f[i][j]=(j*tmp-tmp1+tmp)%mod;
        }
    }
    LL ans=0;
    //1---n+1-j
    for(LL i=1;i<=n;i++)
        for(LL j=1;j<=m;j++)
            s[i][j]=(s[i-1][j]+f[i][j])%mod;
    for(LL i=2;i<=m;i++)
    {
        for(LL j=1;j<=n;j++)
            (ans+=(f[j][i]*s[n+1-j][i])%mod*(m-i+1))%=mod;
    }
    cout<<ans;
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
const int N=2020,M=2020,mod=1000000007;
int n,m,f[N][M]={},ans=0;
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;++i)
		for(int j=f[i][0]=1,s=0;j<m;++j)
		{
			s=(s+f[i-1][j])%mod;
			f[i][j]=(f[i][j-1]+s)%mod;
		}
	for(int i=1;i<=n;++i)
		for(int j=1,s=0,t=1;j<m;++j)
		{
			s=(s+f[n-i][j])%mod;
			t=(t+s)%mod;
			ans=(ans+(long long)f[i][j]*(m-j)%mod*(t+mod-f[n-i][j])%mod)%mod;
		}
	cout<<ans<<endl;
	return 0;
}

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

const int mod = 1e9 + 7;

int exp(int x, int n) {
    int ret = 1;
    while(n) {
        if(n & 1) ret = 1LL * ret * x % mod;
        x = 1LL * x * x % mod;
        n >>= 1;
    }
    return ret;
}
int inv(int x) {
    return exp(x, mod - 2);
}
int fact[10010], invf[10010];
int comb(int n, int k) {
    return 1LL * fact[n] * invf[k] % mod * invf[n - k] % mod;
}

int N, M;
int prec[2010][2010];

int main() {
    fact[0] = 1;
    for(int i = 1; i < 10010; i++) {
        fact[i] = 1LL * fact[i - 1] * i % mod;
    }
    for(int i = 0; i < 10010; i++) {
        invf[i] = inv(fact[i]);
    }

    scanf("%d %d", &N, &M);

    for(int i = 2; i <= M; i++) {
        prec[i][0] = 1;
        for(int j = 1; j < N; j++) {
            prec[i][j] = comb(i + 2 * j - 2, 2 * j);
        }
        for(int j = 1; j < N; j++) {
            prec[i][j] += prec[i][j - 1];
            prec[i][j] %= mod;
        }
    }

    int ans = 0;
    for(int i = 0; i < N; i++) {
        for(int j = 2; j <= M; j++) {
            ans += 1LL * (M - j + 1) * prec[j][i] % mod * (prec[j][N - 1 - i] - (i == N - 1? 0 : prec[j][N - 2 - i])) % mod;
            ans %= mod;
        }
    }

    printf("%d", ans);
}

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
//#include <ctime>
#include <map>
using namespace std;

int n, m;
int C[6001][6001];
long long mod = 1000000007LL;
long long A[2001][2001];
long long B[2001][2001];
long long u[2001], su[2001];

int MAIN()
{
	memset(C, 0, sizeof(C));
	for(int i = 0; i <= 6000; i++)
	{
		C[i][0] = C[i][i] = 1;
		for(int j = 1; j < i; j++)
			C[i][j] = (C[i-1][j-1] + C[i-1][j]) % mod;
	}
	int n, m;
	while(cin >> n >> m)
	{
		memset(A, 0, sizeof(A));
		memset(B, 0, sizeof(B));

		for(int i = 1; i <= n; i++)
		{
			for(int j = 1; j <= m; j++)
			{
				A[i][j] = C[j+2*i-2][2*i];
				A[i][j] += A[i-1][j];
				if(i == 1)
					A[i][j] ++;
				A[i][j] %= mod;
			}
		}
		for(int i = 1; i <= n; i++)
			for(int j = 2; j <= m; j++)
			{
				B[i][j] = A[i][j] - 2 * A[i][j-1] + A[i][j-2];
				if(j == 2) B[i][j] ++;
				B[i][j] %= mod;
				B[i][j] += mod;
				B[i][j] %= mod;
			}

		long long ans = 0;
		for(int len = 2; len <= m; len ++)
		{
			long long t = 0;
			for(int i = 0; i <= n; i++)
			{
				if(i == 0)
					u[i] = 1;
				else
					u[i] = (A[i][len] - B[i][len] + mod) % mod;
				su[i] = u[i];
				if(i > 0)
					su[i] += su[i-1];
				su[i] %= mod;
			}
			for(int i = 0; i <= n-1; i++)
			{
				t += u[i] * su[n-1-i];
				t %= mod;
			}

			ans += t * (m - len + 1);
			ans %= mod;
		}
		cout << ans << endl;
	}
	return 0;
}

int main()
{
	//srand((unsigned)time(NULL));
	#ifdef LOCAL_TEST
		freopen("in.txt", "r", stdin);
		freopen("out.txt", "w", stdout);
	#endif
	ios :: sync_with_stdio(false);
	cout << fixed << setprecision(16);
	return MAIN();
}

#include<bits/stdc++.h>
#define ll long long
#define reg register
#define mp make_pair
#define ri register int
#define ld long double
using namespace std;
const ll md=1000000007;
ll ans,f[2002][2002];
int n,m;
inline void solve(){
	scanf("%d%d",&n,&m);
	for(ri i=1;i<=m;++i)f[1][i]=1;
	for(ri i=2;i<=n;++i){
		int t=0;f[i][1]=1;
		for(ri j=2;j<=m;++j){
			(t+=f[i-1][j])%=md;
			f[i][j]=(f[i][j-1]+t)%md;
		}
	}
	for(ri i=1;i<=n;++i)for(ri j=2;j<=m;++j)(ans+=(m-j+1)*(f[i][j]-f[i-1][j]+md)%md*f[n-i+1][j]%md)%=md;
	printf("%lld\n",ans);
}
int main(){
	ios_base::sync_with_stdio(false);
	int T=1;//cin>>T;
	for(;T--;)solve();
}

#include<bits/stdc++.h>
#define ll long long
const int mo=1e9+7;
const int N=2005;
using namespace std;
int i,j,k,l,n,m;
ll f[N][N],g[N][N],ans,t;
int main(){
    scanf("%d%d",&n,&m);
    for(i=1;i<=n+1;++i){
        for(t=0,j=2;j<=m;++j)
			t=(t+f[i-1][j])%mo,f[i][j]=(f[i][j-1]+t)%mo;
        for(j=2;j<=m;++j)
			f[i][j]++;
    }
    for(i=1;i<=n;++i)
        for(j=2;j<=m;++j)
			ans=(f[i][j]*(f[n-i+1][j]-f[n-i][j])%mo*(m-j+1)+ans)%mo;
    printf("%d\n",(ans+mo)%mo);
}

//start:15:12
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
const int N=2005;
const int mod=1e9+7;
int dp[N][N];
signed main(){
	cin >> n >> m;
	for (int i=1;i<=m;i++) dp[1][i]=1;
	for (int i=2;i<=n;i++){
		dp[i][1]=1;int s=0;
		for (int j=2;j<=m;j++){
			(s+=dp[i-1][j])%=mod;(dp[i][j]+=dp[i][j-1]+s)%=mod;
		}
	}
//	for (int i=1;i<=n;i++){
//		for (int j=1;j<=m;j++) cout << dp[i][j] << ' ';cout << endl;
//	}
	int ans=0;
	for (int i=1;i<=n;i++) for (int j=2;j<=m;j++){
		(ans+=(dp[i][j]-dp[i-1][j]+mod)*dp[n+1-i][j]%mod*(m-j+1))%=mod;
	}
	cout << ans << endl;
	return 0;
}

/*
⣿⣿⣿⣿⣿⣿⡷⣯⢿⣿⣷⣻⢯⣿⡽⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠸⣿⣿⣆⠹⣿⣿⢾⣟⣯⣿⣿⣿⣿⣿⣿⣽⣻⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣻⣽⡿⣿⣎⠙⣿⣞⣷⡌⢻⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⣿⣿⣿⡄⠹⣿⣿⡆⠻⣿⣟⣯⡿⣽⡿⣿⣿⣿⣿⣽⡷⣯⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣟⣷⣿⣿⣿⡀⠹⣟⣾⣟⣆⠹⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⢠⡘⣿⣿⡄⠉⢿⣿⣽⡷⣿⣻⣿⣿⣿⣿⡝⣷⣯⢿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣯⢿⣾⢿⣿⡄⢄⠘⢿⣞⡿⣧⡈⢷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⢸⣧⠘⣿⣷⠈⣦⠙⢿⣽⣷⣻⣽⣿⣿⣿⣿⣌⢿⣯⢿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣟⣯⣿⢿⣿⡆⢸⡷⡈⢻⡽⣷⡷⡄⠻⣽⣿⣿⡿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⣿⣏⢰⣯⢷⠈⣿⡆⢹⢷⡌⠻⡾⢋⣱⣯⣿⣿⣿⣿⡆⢻⡿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⡎⣿⢾⡿⣿⡆⢸⣽⢻⣄⠹⣷⣟⣿⣄⠹⣟⣿⣿⣟⣿⣿⣿⣿⣿⣿⣽⣿⣿⣿⡇⢸⣯⣟⣧⠘⣷⠈⡯⠛⢀⡐⢾⣟⣷⣻⣿⣿⣿⡿⡌⢿⣻⣿⣿
⣿⣿⣿⣿⣿⣿⣧⢸⡿⣟⣿⡇⢸⣯⣟⣮⢧⡈⢿⣞⡿⣦⠘⠏⣹⣿⣽⢿⣿⣿⣿⣿⣯⣿⣿⣿⡇⢸⣿⣿⣾⡆⠹⢀⣠⣾⣟⣷⡈⢿⣞⣯⢿⣿⣿⣿⢷⠘⣯⣿⣿
⣿⣿⣿⣿⣿⣿⣿⡈⣿⢿⣽⡇⠘⠛⠛⠛⠓⠓⠈⠛⠛⠟⠇⢀⢿⣻⣿⣯⢿⣿⣿⣿⣷⢿⣿⣿⠁⣾⣿⣿⣿⣧⡄⠇⣹⣿⣾⣯⣿⡄⠻⣽⣯⢿⣻⣿⣿⡇⢹⣾⣿
⣿⣿⣿⣿⣿⣿⣿⡇⢹⣿⡽⡇⢸⣿⣿⣿⣿⣿⣞⣆⠰⣶⣶⡄⢀⢻⡿⣯⣿⡽⣿⣿⣿⢯⣟⡿⢀⣿⣿⣿⣿⣿⣧⠐⣸⣿⣿⣷⣿⣿⣆⠹⣯⣿⣻⣿⣿⣿⢀⣿⢿
⣿⣿⣿⣿⣿⣿⣿⣿⠘⣯⡿⡇⢸⣿⣿⣿⣿⣿⣿⣿⣧⡈⢿⣳⠘⡄⠻⣿⢾⣽⣟⡿⣿⢯⣿⡇⢸⣿⣿⣿⣿⣿⣿⡀⢾⣿⣿⣿⣿⣿⣿⣆⠹⣾⣷⣻⣿⡿⡇⢸⣿
⣿⣿⣿⣿⣿⣿⣿⣿⡇⢹⣿⠇⢸⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠻⡇⢹⣆⠹⣟⣾⣽⣻⣟⣿⣽⠁⣾⣿⣿⣿⣿⣿⣿⣇⣿⣿⠿⠛⠛⠉⠙⠋⢀⠁⢘⣯⣿⣿⣧⠘⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⡈⣿⡃⢼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡙⠌⣿⣆⠘⣿⣞⡿⣞⡿⡞⢠⣿⣿⣿⣿⣿⡿⠛⠉⠁⢀⣀⣠⣤⣤⣶⣶⣶⡆⢻⣽⣞⡿⣷⠈⣿
⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠘⠁⠉⠉⠉⠉⠉⠉⠉⠉⠉⠙⠛⠛⢿⣄⢻⣿⣧⠘⢯⣟⡿⣽⠁⣾⣿⣿⣿⣿⣿⡃⢀⢀⠘⠛⠿⢿⣻⣟⣯⣽⣻⣵⡀⢿⣯⣟⣿⢀⣿
⣿⣿⣿⣟⣿⣿⣿⣿⣶⣶⡆⢀⣿⣾⣿⣾⣷⣿⣶⠿⠚⠉⢀⢀⣤⣿⣷⣿⣿⣷⡈⢿⣻⢃⣼⣿⣿⣿⣿⣻⣿⣿⣿⡶⣦⣤⣄⣀⡀⠉⠛⠛⠷⣯⣳⠈⣾⡽⣾⢀⣿
⣿⢿⣿⣿⣻⣿⣿⣿⣿⣿⡿⠐⣿⣿⣿⣿⠿⠋⠁⢀⢀⣤⣾⣿⣿⣿⣿⣿⣿⣿⣿⣌⣥⣾⡿⣿⣿⣷⣿⣿⢿⣷⣿⣿⣟⣾⣽⣳⢯⣟⣶⣦⣤⡾⣟⣦⠘⣿⢾⡁⢺
⣿⣻⣿⣿⡷⣿⣿⣿⣿⣿⡗⣦⠸⡿⠋⠁⢀⢀⣠⣴⢿⣿⣽⣻⢽⣾⣟⣷⣿⣟⣿⣿⣿⣳⠿⣵⣧⣼⣿⣿⣿⣿⣿⣾⣿⣿⣿⣿⣿⣽⣳⣯⣿⣿⣿⣽⢀⢷⣻⠄⠘
⣿⢷⣻⣿⣿⣷⣻⣿⣿⣿⡷⠛⣁⢀⣀⣤⣶⣿⣛⡿⣿⣮⣽⡻⣿⣮⣽⣻⢯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢀⢸⣿⢀⡆
⠸⣟⣯⣿⣿⣷⢿⣽⣿⣿⣷⣿⣷⣆⠹⣿⣶⣯⠿⣿⣶⣟⣻⢿⣷⣽⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢀⣯⣟⢀⡇
⣇⠹⣟⣾⣻⣿⣿⢾⡽⣿⣿⣿⣿⣿⣆⢹⣶⣿⣻⣷⣯⣟⣿⣿⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢀⡿⡇⢸⡇
⣿⣆⠹⣷⡻⣽⣿⣯⢿⣽⣻⣿⣿⣿⣿⣆⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠛⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⢸⣿⠇⣼⡇
⡙⠾⣆⠹⣿⣦⠛⣿⢯⣷⢿⡽⣿⣿⣿⣿⣆⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠎⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⢀⣿⣾⣣⡿⡇
⣿⣷⡌⢦⠙⣿⣿⣌⠻⣽⢯⣿⣽⣻⣿⣿⣿⣧⠩⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⢰⢣⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⢀⢀⢿⣞⣷⢿⡇
⣿⣽⣆⠹⣧⠘⣿⣿⡷⣌⠙⢷⣯⡷⣟⣿⣿⣿⣷⡀⡹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣈⠃⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⢀⣴⡧⢀⠸⣿⡽⣿⢀
⢻⣽⣿⡄⢻⣷⡈⢿⣿⣿⢧⢀⠙⢿⣻⡾⣽⣻⣿⣿⣄⠌⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠛⢁⣰⣾⣟⡿⢀⡄⢿⣟⣿⢀
⡄⢿⣿⣷⢀⠹⣟⣆⠻⣿⣿⣆⢀⣀⠉⠻⣿⡽⣯⣿⣿⣷⣈⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⢀⣠⠘⣯⣷⣿⡟⢀⢆⠸⣿⡟⢸
⣷⡈⢿⣿⣇⢱⡘⢿⣷⣬⣙⠿⣧⠘⣆⢀⠈⠻⣷⣟⣾⢿⣿⣆⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⣠⡞⢡⣿⢀⣿⣿⣿⠇⡄⢸⡄⢻⡇⣼
⣿⣷⡈⢿⣿⡆⢣⡀⠙⢾⣟⣿⣿⣷⡈⠂⠘⣦⡈⠿⣯⣿⢾⣿⣆⠙⠻⠿⠿⠿⠿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⢋⣠⣾⡟⢠⣿⣿⢀⣿⣿⡟⢠⣿⢈⣧⠘⢠⣿
⣿⣿⣿⣄⠻⣿⡄⢳⡄⢆⡙⠾⣽⣿⣿⣆⡀⢹⡷⣄⠙⢿⣿⡾⣿⣆⢀⡀⢀⢀⢀⢀⢀⢀⢀⢀⢀⢀⢀⢀⣀⣠⣴⡿⣯⠏⣠⣿⣿⡏⢸⣿⡿⢁⣿⣿⢀⣿⠆⢸⣿
⣿⣿⣿⣿⣦⡙⣿⣆⢻⡌⢿⣶⢤⣉⣙⣿⣷⡀⠙⠽⠷⠄⠹⣿⣟⣿⣆⢙⣋⣤⣤⣤⣄⣀⢀⢀⢀⢀⣾⣿⣟⡷⣯⡿⢃⣼⣿⣿⣿⠇⣼⡟⣡⣿⣿⣿⢀⡿⢠⠈⣿
⣿⣿⣿⣿⣿⣷⣮⣿⣿⣿⡌⠁⢤⣤⣤⣤⣬⣭⣴⣶⣶⣶⣆⠈⢻⣿⣿⣆⢻⣿⣿⣿⣿⣿⣿⣷⣶⣤⣌⣉⡘⠛⠻⠶⣿⣿⣿⣿⡟⣰⣫⣴⣿⣿⣿⣿⠄⣷⣿⣿⣿
*/

#include <bits/stdc++.h>

using namespace std;

#define x first
#define y second
#define mp make_pair
#define pb push_back
#define sqr(a) ((a) * (a))
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define forn(i, n) for(int i = 0; i < int(n); i++)
#define fore(i, l, r) for(int i = int(l); i < int(r); i++)

typedef long long li;
typedef long double ld;
typedef pair<int, int> pt;

template <class A, class B> ostream& operator << (ostream& out, const pair<A, B> &a) {
	return out << "(" << a.x << ", " << a.y << ")";
}

template <class A> ostream& operator << (ostream& out, const vector<A> &v) {
	out << "[";
	forn(i, sz(v)) {
		if(i) out << ", ";
		out << v[i];
	}
	return out << "]";
}

mt19937 rnd(time(NULL));

const int INF = int(1e9);
const li INF64 = li(1e18);
const int MOD = int(1e9) + 7;
const ld EPS = 1e-9;
const ld PI = acos(-1.0);

const int N = 2000 + 7;

int n, m;

bool read () {
	if (scanf("%d%d", &n, &m) != 2)
		return false;
	return true;
}

int add(int a, int b){
	a += b;
	if (a >= MOD)
		a -= MOD;
	if (a < 0)
		a += MOD;
	return a;
}

int mul(int a, int b){
	return a * li(b) % MOD;
}

int val[N];
int dp[N][N];
int pr1[N], pr2[N];

void solve() {
	memset(dp, 0, sizeof(dp));
	fore(len, 2, m + 1)
		dp[0][len] = 1;
	fore(rows, 1, n + 1){
		int cur = 0;
		int sum = 0;
		fore(len, 2, m + 1){
			sum = add(sum, dp[rows - 1][len]);
			cur = add(cur, sum);
			dp[rows][len] = cur;
		}
	}
	int ans = 0;
	fore(len, 2, m + 1){
		forn(rows, n)
			pr1[rows + 1] = add(pr1[rows], dp[rows][len]);
		pr2[1] = 1;
		fore(rows, 1, n)
			pr2[rows + 1] = add(pr2[rows], add(dp[rows][len], -dp[rows - 1][len]));
		forn(h, n)
			ans = add(ans, mul(m - len + 1, mul(pr1[h + 1], pr2[n - h])));
	}
	printf("%d\n", ans);
}

int main() {
#ifdef _DEBUG
	freopen("input.txt", "r", stdin);
//	freopen("output.txt", "w", stdout);

	int tt = clock();

#endif

	cerr.precision(15);
	cout.precision(15);
	cerr << fixed;
	cout << fixed;

	while(read()) {
		solve();

#ifdef _DEBUG
	cerr << "TIME = " << clock() - tt << endl;
	tt = clock();
#endif

	}
}

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define mod 1000000007
#define N 2005
using namespace std;
ll dp[N][N];
int n,m;
ll ans=0;
int main(){
 scanf("%d%d",&n,&m);
 for(int i=1;i<=m;i++)dp[1][i]=1;
 for(int i=2;i<=n;i++)
 {int sum=0;
 dp[i][1]=1;
 for(int r=2;r<=m;r++)
 sum+=dp[i-1][r],sum%=mod,dp[i][r]=(dp[i][r-1]+sum)%mod;
 }
 for(int i=1;i<=n;i++)
 for(int r=2;r<=m;r++)
 ans=(ans+mod+((dp[i][r]-dp[i-1][r])*dp[n-i+1][r]%mod)*(m-r+1))%mod;
 cout<<ans;
}

#include <algorithm>

#include <stdio.h>

#include <memory.h>

#include <queue>

#include <cmath>

#include <set>

#include <map>

#include <string.h>

#include <string>

#include <ctype.h>

using namespace std;

typedef long long INT;

typedef pair<int, int> pii;

#define beyond(r, c) (r<0 || c<0 || r>=R || c>=C)

#define NN 2100

#define MOD 1000000007

INT s1[NN][NN], sum[NN][NN], cnt[NN][NN], cnt1[NN][NN];

int main() {

	int n, m, i, j;

	INT res;

	scanf("%d%d", &n, &m);

	for (i=2; i<=m; i++) {

		for (j=1; j<=n; j++) {

			cnt[i][j]=sum[i][j-1]+1;

			cnt[i][j]%=MOD;

			s1[i][j]=s1[i-1][j]+cnt[i][j];

			s1[i][j]%=MOD;

			sum[i][j]=sum[i-1][j]+s1[i][j];

			sum[i][j]%=MOD;

			cnt1[i][j]=cnt[i][j]-cnt[i][j-1];

			if (cnt1[i][j]<0) cnt1[i][j]+=MOD;

		}

	}

	res=0;

	for (i=2; i<=m; i++) for (j=1; j<=n; j++) {

		res+=((cnt[i][j]*cnt1[i][n-j+1])%MOD)*(m-i+1);

		res%=MOD;

	}

	printf("%I64d\n", res);

	return 0;

}

#include<cstdio>
using namespace std;
const long long p=1000000007;
int n,m;
long long a[2010][2010],ans;
int main()
  {
   scanf("%d%d",&n,&m);
   for (int i=1;i<=m;i++) a[1][i]=1;
   for (int i=2;i<=n;i++)
     {
      a[i][1]=1;
      long long sum=0;
      for (int j=2;j<=m;j++)
        {
         sum=(sum+a[i-1][j])%p;
         a[i][j]=(a[i][j-1]+sum)%p;
		}
	 }
   long long ans=0;
   for (int i=1;i<=n;i++)
     for (int j=2;j<=m;j++)
       ans=(ans+(a[i][j]-a[i-1][j]+p)%p*a[n-i+1][j]%p*(m-j+1)%p)%p;
   printf("%lld",ans);
   return 0;
  }

#include <bits/stdc++.h>
#define endl '\n'

using namespace std;
struct custom_hash
{
    static unsigned long long splitmix64(unsigned long long x)
    {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(unsigned long long x) const
    {
        static const unsigned long long FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
mt19937 random_generator(chrono::steady_clock::now().time_since_epoch().count());

const int maxn = 2003;
const int mod = 1e9 + 7;

int n, m;
void read()
{
	cin >> n >> m;
}

int add(int a, int b)
{
	a += b;
	if (a >= mod)
	a -= mod;

	return a;
}

int dp[maxn][maxn];
int incr[maxn][maxn];
int pr_sum[maxn][maxn];
int f1[maxn][maxn], f2[maxn][maxn];
void solve()
{
	if (m == 1)
	{
		cout << 0 << endl;
		return;
	}

	for (int i = 2; i <= m; i++)
	incr[1][i] = 1, pr_sum[1][i] = add(pr_sum[1][i-1], incr[1][i]);

	for (int i = 2; i <= n; i++)
	for (int j = 2; j <= m; j++)
	{
		incr[i][j] = add(incr[i][j-1], pr_sum[i-1][j]);
	    pr_sum[i][j] = add(pr_sum[i][j-1], incr[i][j]);
	}

	for (int i = 1; i <= n; i++)
	for (int j = 2; j <= m; j++)
	f1[i][j] = add(f1[i][j-1], pr_sum[i][j]);

	for (int i = 1; i <= n; i++)
	for (int j = 2; j <= m; j++)
	f2[i][j] = add(f1[i][j], mod - incr[i][j]);

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

	for (int i = 2; i <= n; i++)
	{
		int sum1 = 0, sum2 = 0;
		for (int j = m; j >= 2; j--)
	    {
		   dp[i][j] = 1ll * f2[i-1][j] * (m - j + 1) % mod;

		   sum2 = add(sum2, dp[i-1][j]);
		   sum1 = add(sum1, sum2);

		   dp[i][j] = add(dp[i][j], sum1);
	    }
	}

	int ans = 0;
	for (int i = 1; i <= n; i++)
	for (int j = 2; j <= m; j++)
	ans = add(ans, 1ll * dp[i][j] * (n - i + 1) % mod);

	cout << ans << endl;
}

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);

	read();
	solve();
}

#include<cstdio>
const int mod = 1000000007;
using namespace std;
int f[2013][2013] , g[2013][2013];
void Add(int &a,int b)
{
    a += b;
    if(a >= mod) a -= mod;
}
int main()
{
    int n , m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        int sum = 0;
        for(int j=2;j<=m;j++)
        {
            Add(f[i][j],g[i-1][j]+1);
            Add(sum,f[i][j]);
            Add(g[i][j],g[i][j-1]+sum);
        }
    }
    int ans = 0;
    for(int i=1;i<=n;i++)
    {
        for(int j=2;j<=m;j++)
        {
            ans += (long long)f[i][j]*(g[n-i][j]-f[n-i][j]+1)%mod*(m-j+1)%mod;
            ans%=mod;
        }
    }
    printf("%d\n",ans);
    return 0;
}

/*
读题不规范，爆零两行泪。
数据不清空，爆零两行泪。
多测不读完，爆零两行泪。
边界不特判，爆零两行泪。
贪心不证明，爆零两行泪。
D P 顺序错，爆零两行泪。
大小少等号，爆零两行泪。
变量不统一，爆零两行泪。
越界不判断，爆零两行泪。
调试不注释，爆零两行泪。
溢出不 l l，爆零两行泪。
*/
#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
const int N=2000,M=N;
int n,m;
int dp[N+1][M+1];
int Sum[N+1][M+1],Sumk[N+1][M+1];
int sum[N+2];
int main(){
	cin>>n>>m;
	for(int i=2;i<=m;i++)dp[1][i]=1,Sum[1][i]=(Sum[1][i-1]+dp[1][i])%mod,Sumk[1][i]=(Sumk[1][i-1]-1ll*i*dp[1][i])%mod;
	for(int i=2;i<=n;i++)for(int j=2;j<=m;j++){
		dp[i][j]=(1ll*(j+1)*Sum[i-1][j]+Sumk[i-1][j]+1)%mod;
		Sum[i][j]=(Sum[i][j-1]+dp[i][j])%mod;
		Sumk[i][j]=(Sumk[i][j-1]-1ll*j*dp[i][j])%mod;
	}
	int ans=0;
	for(int k=2;k<=m;k++){
		for(int j=n;j;j--)sum[j]=(1ll*sum[j+1]+dp[n-j+1][k]-dp[n-j][k])%mod;
		for(int i=1;i<=n;i++)(ans+=1ll*(m-k+1)*(dp[i][k]-dp[i-1][k])%mod*sum[i]%mod)%=mod;
	}
	cout<<(ans+mod)%mod;
	return 0;
}

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define inc(i) (++ (i))
#define dec(i) (-- (i))
#define Rep(i , a , b) for(int i = (a) , i##Limit = (b) ; i <= i##Limit ; inc(i))
#define rep(i , a , b) for(int i = (a) , i##Limit = (b) ; i >= i##Limit ; dec(i))
using namespace std;

const int N = 4000 + 7 , Mod = 1000000000 + 7;
int n , m , Dp[N][N] , Sum , Ans;

int main() {
	cin >> n >> m;
    Rep(i , 1 , m) Dp[1][i] = 1;
    Rep(i , 2 , n) {
        Sum = 0 , Dp[i][1] = 1;
        Rep(j , 2 , m)
            (Sum += Dp[i - 1][j]) %= Mod , Dp[i][j] = (Dp[i][j - 1] + Sum) % Mod;
    }
    Rep(i , 1 , n)
        Rep(j , 2 , m)
            (Ans += 1ll * (Dp[i][j] - Dp[i - 1][j] + Mod) * Dp[n - i + 1][j] % Mod * (m - j + 1) % Mod) %= Mod;
    printf("%d" , Ans);
	return 0;
}

#include<bits/stdc++.h>

using namespace std;

#define FOR(i, x, y) for(int i = (x); i < (y); ++i)
#define REP(i, x, y) for(int i = (x); i <= (y); ++i)
#define PB push_back
#define MP make_pair
#define PH push
#define fst first
#define snd second
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<int, int> pii;

const int maxn = 2005;
const int INF = 1e9 + 7;

int n, m, ans;
int f[maxn][maxn], sum[maxn], prod[maxn], g[maxn][maxn];

inline int add(const int &x, const int &y){ return (x + y) - (x + y > INF ? INF : 0); }
inline int sub(const int &x, const int &y){ return (x - y) + (x - y < 0 ? INF : 0); }
inline int mul(const int &x, const int &y){ return 1ll * x * y % INF; }
inline int& uadd(int &x, const int &y){ return (x += y) -= (x >= INF ? INF : 0); }

int main(){
	scanf("%d%d", &n, &m);
	FOR(i, 0, n) REP(j, 0, m - 2){
		f[i + 1][j] = add(sub(mul(j + 1, sum[j]), prod[j]), 1);
		sum[j] = add(j ? sum[j - 1] : 0, f[i + 1][j]);
		prod[j] = add(j ? prod[j - 1] : 0, mul(f[i + 1][j], j));
		g[i + 1][j] = sum[j];
	}

	REP(i, 1, n){
		REP(j, 0, m - 2){
			sum[j] = add(j ? sum[j - 1] : 0, f[n - i][j]);
			prod[j] = add(j ? prod[j - 1] : 0, mul(f[n - i][j], j));
		}
		REP(j, 0, m - 2)
			uadd(ans, mul(mul(f[i][j], m - j - 1), add(j ? sub(mul(j + 1, sum[j - 1]), prod[j - 1]) : 0, 1)));
	}

	printf("%d\n", ans);
	return 0;
}

#include <iostream>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <queue>
#define int long long int

using namespace std;

main()
{
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    int N, M;
    int mod = 1e9+7;
    cin>>N>>M;
    vector<vector<int> > D(N, vector<int>(M+1));
    vector<vector<int> > Sum(N, vector<int>(M+1));
    vector<vector<int> > Sum2(N, vector<int>(M+1));
    for(int len = 2; len <= M; ++ len)
    {
        D[0][len] = 1;
        Sum[0][len] = (Sum[0][len-1] + D[0][len]) % mod;
        Sum2[0][len] = (Sum2[0][len-1] + Sum[0][len]) % mod;
    }
    for(int i = 1; i < N; ++ i)
    {
        for(int len = 2; len <= M; ++ len)
        {
            D[i][len] = (1 + Sum2[i-1][len]) % mod;
            Sum[i][len] = (Sum[i][len-1] + D[i][len]) % mod;
            Sum2[i][len] = (Sum2[i][len-1] + Sum[i][len]) % mod;
            //cout<<i<<' '<<len<<' '<<D[i][len]<<endl;
        }
    }
    int ans = 0;
    int i = 0;
    for(int len = 2; len <= M; ++ len)
    {
        ans = (ans + ((M-len+1) * D[N-1-i][len]) % mod) % mod;
    }
    //cout<<ans<<endl;
    for(int i = 1; i < N; ++ i)
    {
        for(int len = 2; len <= M; ++ len)
        {
            ans = (ans + (M-len+1) * ((((D[i][len] - D[i-1][len] + mod) % mod) * D[N-1-i][len]) % mod) % mod) % mod;
        }
    }
    cout<<ans<<endl;
}

#include<bits/stdc++.h>
#define god dimasi5eks
#pragma GCC optimize("O3")
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define mod 1000000007
#define dancila 3.14159265359
#define eps 1e-9

using namespace std;

typedef long long ll;

int add(int a, int b)
{
    ll x = a+b;
    if(x >= mod)
        x -= mod;
    if(x < 0)
        x += mod;
    return x;
}
ll mul(ll a, ll b)
{
    return (a*b) % mod;
}

ll pw(ll a, ll b)
{
    ll ans = 1;
    while(b)
    {
        if(b & 1)
            ans = (ans * a) % mod;
        a = (a * a) % mod;
        b >>= 1;
    }
    return ans;
}
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
long long rand_seed()
{
    long long a = rng();
    return a;
}
ll n, m, dp[2002][2002];
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> n >> m;
    for(int i = 1; i <= m; ++i)
        dp[1][i] = 1;
    for(int i = 2; i <= n; ++i)
    {
        dp[i][1] = 1;
        ll sum = 0;
        for(int j = 2; j <= m; ++j)
        {
            sum = add(sum, dp[i-1][j]);
            dp[i][j] = add(sum, dp[i][j-1]);
        }
    }
    ll ans = 0;
    for(int i = 1; i <= n; ++i)
        for(int j = 2; j <= m; ++j)
        {
            ll tba = add(dp[i][j], -dp[i-1][j]);
            tba = mul(tba, dp[n - i + 1][j]);
            tba = mul(tba, m - j + 1);
            ans = add(ans, tba);
        }
    cout << ans;
    return 0;
}

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=2005;
#define mod 1000000007
int n,m,dp[maxn][maxn];
void add(int &x,int y)
{
    x=x+y>=mod?x+y-mod:x+y;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)dp[1][i]=1;
    for(int i=2;i<=n;i++)
    {
        int sum=0;
        dp[i][1]=1;
        for(int j=2;j<=m;j++)
        {
            add(sum,dp[i-1][j]);
            add(dp[i][j],dp[i][j-1]+sum);
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=2;j<=m;j++)
            add(ans,(ll)(dp[i][j]-dp[i-1][j]+mod)*dp[n-i+1][j]%mod*(m-j+1)%mod);
    printf("%d\n",ans);
    return 0;
}//hello

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

namespace TYC
{
	typedef long long ll;
	const ll p=1000000007;
	const int N=2010;
	int n,m;
	ll ans,dp[N][N],sum[N][N],sumk[N][N];

	inline void Mod(ll &x) {x=(x>=p?x-p:x);}

	void work()
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=m;i++)
		{
			dp[1][i]=1;
			if(i!=1)
			{
				sum[1][i]=sum[1][i-1]+1;
				sumk[1][i]=sumk[1][i-1]+i;
			}
		}
		for(int i=2;i<=n;i++)
		{
			dp[i][1]=1;
			for(int j=2;j<=m;j++)
			{
				Mod(dp[i][j]=(sum[i-1][j]*(j+1)%p-sumk[i-1][j]+1+p));
				Mod(sum[i][j]=sum[i][j-1]+dp[i][j]);
				Mod(sumk[i][j]=sumk[i][j-1]+dp[i][j]*j%p);
			}
		}
		for(int i=1;i<=n;i++)
			for(int j=2;j<=m;j++)
				Mod(ans+=(dp[i][j]-dp[i-1][j]+p)*dp[n-i+1][j]%p*(m-j+1)%p);
		printf("%lld\n",ans);
	}
}

int main()
{
	TYC::work();
	return 0;
}

/* 2013-07-26 09:26:54.455070 */#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <iostream>
using namespace std;

const long long mod = 1000000007;
const int MAXN = 2005;
int n, m;
long long f[MAXN][MAXN], g[MAXN][MAXN];

int main() {

	scanf("%d %d", &n, &m);

	for(int i = 2; i <= m; i++)
		f[1][i] = 1;
	for(int i = 2; i <= n; i++) {
		long long sum = 0, summ = 0;
		for(int j = 2; j <= m; j++) {
			sum = (sum + f[i - 1][j]) % mod;
			summ = (summ + f[i - 1][j] * j % mod) % mod;
			f[i][j] = (-summ + sum * (j + 1) % mod + mod) % mod;
		}
	}
	for(int i = 2; i <= m; i++)
		g[0][i] = 1;
	for(int i = 1; i <= n; i++) {
		long long sum = 0, summ = 0;
		for(int j = 1; j <= m; j++) {
			g[i][j] = (-summ + sum * (j + 1) % mod + mod) % mod;
			sum = (sum + f[i][j]) % mod;
			summ = (summ + f[i][j] * j % mod) % mod;
		}
	}
	long long ans = 0;
	for(int i = 2; i <= m; i++) {
		long long sum1 = 0;
		for(int j = 1; j <= n; j++) {
			sum1 = (sum1 + f[j][i]) % mod;
		}
		long long sum2 = g[0][i], res = 0;
		for(int j = n; j >= 1; j--) {
			res = (res + sum1 * sum2 % mod) % mod;
			sum2 = (sum2 + g[n - j + 1][i]) % mod;
			sum1 = (sum1 - f[j][i] + mod) % mod;
		}
		ans = (ans + res * (m - i + 1) % mod) % mod;
	}
	cout << ans << endl;
	return 0;
}

#include <iostream>
#include <algorithm>
using namespace std;

typedef long long LL;
const int MAXN = 2000 + 86;
const int MOD = 1000000007;

int f[MAXN][MAXN], g[MAXN][MAXN];

int main() {
	ios_base::sync_with_stdio(false);

	int n, m;
	int tot = 0;
	cin >> n >> m;
	for (int i=1; i<=m; ++i) f[1][i] = g[1][i] = 1;
	for (int i=2; i<=n; ++i) {
		for (int j=2; j<=m; ++j) {
			f[i][j] = (2ll * f[i][j-1] - f[i][j-2] + f[i-1][j]) % MOD;
			g[i][j] = (g[i-1][j] + f[i][j]) % MOD;
		}
	}
	for (int t=1; t<=n; ++t) for (int k=2; k<=m; ++k) {
		int cc = g[t][k] * (0ll + f[n-t+1][k]) % MOD;
		cc = cc * (m - k + 1ll) % MOD;
		tot = (tot + cc) % MOD;
	}
	if (tot < 0) tot += MOD;
	cout << tot << endl;

	return 0;
}

//  Be name khoda
// "Khodaya, be man "Tagwaye setiz" biamooz ta
//  dar anbuh masuliat nalaghzam ..." -Shariati
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

#define F first
#define S second
#define MP make_pair

const int MAX = 2000+9;
const ll MOD = 1e9+7;

int dp1[MAX][MAX], dp2[MAX][MAX];

int main () {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int n, m;
	cin >> n >> m;
	// dp1
	fill(dp1[0], dp1[0] + MAX, 1);
	for (int i = 1; i < n; i++) {
		int sum1 = 0, sum2 = 0;
		for (int t = 0; t < m; t++) {
			sum1 = (sum1 + dp1[i-1][t]) % MOD;
			sum2 = (sum2 + sum1) % MOD;
			dp1[i][t] = (sum2 + 1) % MOD;
		}
	}
	// dp2
	fill(dp2[n-1], dp2[n-1] + MAX, 1);
	for (int i = n-2; i >= 0; i--) {
		int sum1 = 0, sum2 = 0;
		int k = n-i-2;
		for (int t = 0; t < m; t++) {
			sum2 = (sum2 + sum1) % MOD;
			dp2[i][t] = (sum2 + 1) % MOD;
			sum1 = (sum1 + dp1[k][t]) % MOD;
			sum2 = (sum2 + dp1[k][t]) % MOD;
		}
	}
	ll res = 0;
	for (int i = 0; i < n; i++)
		for (int t = 0; t <= m-2; t++) {
			ll f = m-t-1;
			f = f * dp1[i][t] % MOD * dp2[i][t] % MOD;
			res = (res + f) % MOD;
		}
	cout << res << "\n";
}

#include<bits/stdc++.h>
using namespace std;
const int N=2005,mod=1e9+7;
int n,m,dp[N][N],sum[N][N],ans;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		for(int j=2;j<=m;j++)
			dp[i][j]=(dp[i][j-1]+sum[i-1][j]+(j==2))%mod;
		for(int j=2;j<=m;j++)
			sum[i][j]=(sum[i][j-1]+dp[i][j])%mod;
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=2;j<=m;j++)
		{
			int x=(dp[i][j]-dp[i-1][j]+mod)%mod;
			x=1ll*x*dp[n-i+1][j]%mod;
			x=1ll*x*(m-j+1)%mod;
			ans=(ans+x)%mod;
		}
	}
	printf("%d\n",ans);
	return 0;
}

#include <vector>
#include <algorithm>

using namespace std;

const int MAXN = 2012;
const long long MOD = 1000000007LL;

long long dp[MAXN][MAXN][2];

int main() {
  int n, m;
  long long x, y, ans;

  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; ++i) {
    for (int j = 2; j <= m; ++j) {
      dp[i][j][0] = 1;
    }
  }
  ans = 0;
  for (int i = 1; i <= n; ++i) {
    // 0->0
    y = x = 0;
    for (int j = 2; j <= m; ++j) {
      x = (x + dp[i - 1][j][0]) % MOD;
      y = (y + x) % MOD;
      dp[i][j][0] += y;
    }
    // 0->1
    y = x = 0;
    for (int j = m; j >= 2; --j) {
      dp[i][j][1] += (y + x) % MOD;
      x = (x + dp[i - 1][j][0] * (m + 1 - j)) % MOD;
      y = (y + x) % MOD;
    }
    // 1->1
    y = x = 0;
    for (int j = m; j >= 2; --j) {
      x = (x + dp[i - 1][j][1]) % MOD;
      y = (y + x) % MOD;
      dp[i][j][1] += y;
    }
    // ans
    for (int j = 2; j <= m; ++j) {
      ans = (ans + dp[i][j][0] * (m + 1 - j) + dp[i][j][1]) % MOD;
    }
  }
  ans = (ans + MOD) % MOD;
  printf("%d\n", (int)ans);

  return 0;
}

#include <cstdio>

const long long mod_v = 1000000007;
const int MaxN = 2001;
long long f[MaxN][MaxN];

int main()
{
	int n, m;
	std::scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; ++i)
	{
		long long s1 = 0, s2 = 0;
		for(int j = 2; j <= m; ++j)
		{
			s1 = (s1 + f[i - 1][j]) % mod_v;
			s2 = (s2 + j * f[i - 1][j]) % mod_v;
			f[i][j] = (1 + (j + 1) * s1 - s2) % mod_v;
		}
	}

	long long ans = 0;
	for(int i = 1; i <= n; ++i)
		for(int j = 2; j <= m; ++j)
			ans = (ans + (m - j + 1) * f[i][j] % mod_v * (f[n - i + 1][j] - f[n - i][j])) % mod_v;

	if(ans < 0) ans += mod_v;
	std::printf("%d\n", (int)ans);

	return 0;
}

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
const int P=1000000007;
int n,m,dp[2003][2004];
int main(){
	scanf("%d%d",&n,&m);
	for(int j=2;j<=m;j++) dp[1][j]=1;
	for(int i=2;i<=n;i++){
		LL s1=0,s2=0;
		for(int j=2;j<=m;j++){
			s1+=dp[i-1][j];
			if(s1>=P) s1-=P;
			s2+=s1;
			if(s2>=P) s2-=P;
			dp[i][j]=s2;
		}
	}

	for(int i=2;i<=n;i++){
		for(int j=2;j<=m;j++){
			dp[i][j]+=dp[i-1][j];
			if(dp[i][j]>=P) dp[i][j]-=P;
		}
	}

	LL ans=0;
	for(int i=1;i<=n;i++){
		for(int j=2;j<=m;j++){
			ans=(ans+(LL)(m-j+1)*(dp[i][j]-dp[i-1][j])%P*dp[n-i+1][j])%P;
//			if(j==2) cout<<i<<" "<<(m-j+1)*(dp[i][j]-dp[i-1][j])*dp[n-i+1][j]<<endl;
		}

	}
	cout<<(ans+P)%P<<endl;
	return 0;
}

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define mod 1000000007
using namespace std;

int n,m,i,j;
int f[2222][2222];
int t[2222][2222];
int s[2222][2222];
int *ff,*ss,*tt;
int ans,cur;

int main()
{
//	freopen("295D.in","r",stdin);
//	freopen("295D.out","w",stdout);

	scanf("%d%d",&n,&m);
	if (m==1) { printf("0\n"); return 0; }
//	m--;

	ff=f[0];
	tt=t[0];
	for (i=1;i<m;i++)
	{
		ff[i]=1;
		tt[i]=1;
	}

	for (i=1;i<n;i++)
	{
		ss=s[i];
		ff=f[i];
		tt=t[i];
		ss[0]=0;
		ff[0]=0;
		for (j=1;j<m;j++)
		{
			ss[j]=(ss[j-1]+f[i-1][j])%mod;
			ff[j]=(ff[j-1]+ss[j])%mod;
			tt[j]=(t[i-1][j]+ff[j])%mod;
		}
	}

	ans=0;
	for (i=1;i<m;i++)
	{
		cur=0;
		for (j=0;j<n;j++)
			cur=(cur+(int)(1ll*f[j][i]*t[n-j-1][i]%mod))%mod;
		ans=(ans+(int)((m-i|0ll)*cur%mod))%mod;
	}

	printf("%d",ans);

	return 0;
}

#include<cstdio>

#define N 2010
#define mo 1000000007

using namespace std;

int n,m,ans,nowsum;
int f[N][N],sf[N][N];

int main()
{
	scanf("%d%d",&n,&m);
	for(int j=0;j<=m-2;j++)
			f[1][j]=1;
	for(int i=2;i<=n;i++)
	{
		nowsum=0;
		for(int j=0;j<=m-2;j++)
		{
			nowsum+=f[i-1][j];
			if(nowsum>=mo)nowsum-=mo;
			f[i][j]=f[i][j-1]+nowsum;
			if(f[i][j]>=mo)f[i][j]-=mo;
		}
	}
	for(int i=1;i<=n;i++)
		for(int j=0;j<=m-2;j++)
		{
			sf[i][j]=sf[i-1][j]+f[i][j];
			if(sf[i][j]>=mo)sf[i][j]-=mo;
		}
	for(int i=1;i<=n;i++)
		for(int j=0;j<=m-2;j++)
		{
			ans+=1ll*sf[i][j]*f[n-i+1][j]%mo*(m-j-1)%mo;
			if(ans>=mo)ans-=mo;
		}
	printf("%d",ans);
}

#include<bits/stdc++.h>
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define Rep(i,a,b) for(register int i=(a);i<=int(b);++i)
#define Dep(i,a,b) for(register int i=(a);i>=int(b);--i)
#define rep(i,a,b) for(register int i=(a);i<int(b);++i)
#define mem(x,v) memset(x,v,sizeof(x))
#define fi first
#define se second
#define debug(x) cout << #x" = " << x << endl;
#define pp(x,y) cout << "pp: " << x << " " << y << endl;
namespace IO{
	const int L=1<<15;char ibuf[L|1],*iS=ibuf,*iT=ibuf,obuf[L|1],*oS=obuf,*oT=obuf+L,c,st[66];int tp=0,f;
	inline char gc(){if(iS==iT) iT=(iS=ibuf)+fread(ibuf,sizeof(char),L,stdin);return (*iS++);}
	inline void flush(){fwrite(obuf,sizeof(char),oS-obuf,stdout);oS = obuf;}
	inline void pc(char c){*oS++=c;if(oS==oT) flush();}
	#define gc getchar
	#define pc putchar
	inline ll read(){ll x=0;f=1,c=gc();for(;!isdigit(c);c=gc())if(c=='-')f=-1;for(;isdigit(c);c=gc())x=(x<<1)+(x<<3)+(c&15);return x*f;}
	inline void write(ll x){if(!x) pc('0');if(x<0) pc('-'),x=-x;while(x) st[++tp]=x%10+'0',x/=10;while(tp) pc(st[tp--]);}
	inline void writeln(ll x){write(x);pc('\n');}
	inline void wri(ll x){write(x),pc(' ');}
	struct IOflusher{~IOflusher(){flush();}}_ioflusher_;
}using IO::read;using IO::write;using IO::writeln;using IO::wri;//using IO::gc;using IO::pc;
const int mod = 1e9+7;
int n,m,f[2005][2005],g[2005][2005];
void add(int &x,int v){
	x+=v;
	if(x>=mod) x-=mod;
	if(x<0) x+=mod;
}
int main(){
	n = read(),m = read();
	for(int i=1;i<=n;++i){
		int ps = 0,pt = 0;
		for(int j=2;j<=m;++j){
			f[i][j] = 0;
		//	for(int k=2;k<=j;++k){
			add(ps,f[i-1][j]);
			add(pt,1ll * f[i-1][j] * j % mod);
//			ps += f[i-1][j];
//			pt += f[i-1][j] * j;
//				f[i][j] += f[i-1][k] * (j+1) + f[i-1][k] * -k;
			add(f[i][j],mod-pt);
			add(f[i][j],1ll*ps*(j+1)%mod);
			add(f[i][j],1);
//			f[i][j] -= pt;
//			f[i][j] += ps * (j+1);//f[i-1][k] * (j+1);
//			f[i][j]++;
		}//枚举这个长度
	}
	int ans = 0;
	for(int i=1;i<=n;++i){
		for(int j=2;j<=m;++j){
			add(ans,1ll * f[i][j] * (f[n-i+1][j] - f[n-i][j] + mod) % mod * (m-j+1) % mod);
//			ans += f[i][j] * (f[n-i+1][j] - f[n-i][j]) * (m-j+1);
		}
	}
	writeln(ans);
	return 0;
}

#include<stdio.h>
#include<cmath>
#include<utility>
#include<algorithm>
using namespace std;
//#define TEST
#define llong long long
llong N, M, prime = 1000000007;
llong dp[2005][2005] = {0};
int main()
{
    FILE *INPUT = stdin;
#ifdef TEST
    INPUT = fopen("input.txt", "r");
#endif
    fscanf(INPUT, "%d%d",&N,&M);
    int i1 = 0, i2 = 0, i3 = 0;
    llong val1 = 0, val2 = 0, val3 = 0;
    for( i1 = 1; i1 <= N; ++ i1)
    {
        val1 = 0;
        val2 = 1;
        for( i2 = 2; i2 <= M; ++ i2)
        {
            val1 = (val1 + dp[i1 - 1][i2]) % prime;
            val2 = (val1 + val2) % prime;
            dp[i1][i2] = val2;
        }
    }
    llong caves = 0;
    for( i1 = 2; i1 <= M; ++ i1)
    {
        val1 = 0;
        val2 = 0;
        for( i2 = 1; i2 <= N; ++ i2)
        {
            val1 = dp[i2][i1] - dp[i2 - 1][i1];
            val2 = (val2 + val1 * dp[N - i2 + 1][i1]) % prime;
        }
        val2 = (val2 * (M - i1 + 1)) % prime;
        caves = (caves + val2) % prime;
    }
    printf("%d\n", (prime + caves) % prime);
    return 0;
}

#include<bits/stdc++.h>
#define mk make_pair
#define fi first
#define nd second
#define pii pair<int,int>
#define pb push_back
#define sqr(x) ((x)*(x))
using namespace std;
typedef long long ll;
inline ll read() {ll x = 0; char ch = getchar(), w = 1;while(ch < '0' || ch > '9') {if(ch == '-') w = -1;
ch = getchar();}while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}return x * w;}
void write(ll x) {if(x < 0) putchar('-'), x = -x;if(x > 9) write(x / 10);putchar(x % 10 + '0');}
inline void writeln(ll x) {write(x);puts("");}
const int N = 110000;
const ll p = 1e9 + 7;
int n, m;
ll f[2100][2100], ans;

int main() {
	n = read();m = read();
	f[0][0] = 1;
	for(int i = 1; i <= n; ++i) {
		f[i][0] = 1;
		ll sum = 1, res = 0;
		for(int j = 2; j <= m; ++j) {
			res += f[i - 1][j];
			res %= p;
			sum += res;
			sum %= p;
			f[i][j] = sum;
		}
	}
/*	for(int i = 1; i <= n; ++i)
		for(int j = 2; j <= m; ++j)
			for(int k = 1; k <= j; ++k)
				(ans += (f[i][j] - f[i - 1][j])* f[n - i][k]  * (j - k + 1)) %= p;*/
	for(int i = 1; i <= n; ++i)
		for(int j = 2; j <= m; ++j)
			(ans += (f[i][j] - f[i - 1][j] )* f[n - i + 1][j]  % p * (m - j + 1)) %= p;
	ans = (ans + p) % p;
	writeln(ans);
}

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<ctime>
#include<cstdlib>
#include<string>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#include<bitset>
#include<vector>
#define re register
#define rep(x,a,b) for (re int x=int(a);x<=(int)(b);x++)
#define drp(x,a,b) for (re int x=int(a);x>=(int)(b);x--)
#define cross(x,a) for (re int x=hd[a];~x;x=nx[x])
#define LL long long
#define mo 1000000007
#define N 2010
using namespace std;
inline LL read(){
    LL x=0;int ch=getchar(),f=1;
    while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
    if (ch=='-'){f=-1;ch=getchar();}
    while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
int n,m,f[N][N];
int main(){
	n=read(),m=read();
	rep(i,1,m) f[1][i]=1;
	rep(i,2,n){
		int sum=0;f[i][1]=1;
		rep(j,2,m){
			sum=(sum+f[i-1][j])%mo;
			f[i][j]=(f[i][j]+f[i][j-1]+sum)%mo;
		}
	}
	int ans=0;
	rep(i,1,n)
		rep(j,2,m)
			ans=(ans+(LL)(f[i][j]-f[i-1][j]+mo)%mo*f[n-i+1][j]%mo*(m-j+1)%mo)%mo;
	printf("%d\n",ans);
	return 0;
}

#include<bits/stdc++.h>
#define For(i,x,y) for (register int i=(x);i<=(y);i++)
#define Dow(i,x,y) for (register int i=(x);i>=(y);i--)
#define cross(i,k) for (register int i=first[k];i;i=last[i])
using namespace std;
typedef long long ll;
inline ll read(){
    ll x=0;int ch=getchar(),f=1;
    while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
    if (ch=='-'){f=-1;ch=getchar();}
    while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
const int N = 2010, mod = 1e9+7;
int n,m;
int dp[N][N],sum[N][N],Sum[N][N];
inline void init(){
	n=read(),m=read();
	For(i,0,m-2) dp[1][i]=1,sum[1][i]=sum[1][i-1]+1,Sum[1][i]=Sum[1][i-1]+i;
	For(i,2,n)
		For(j,0,m-2){
			dp[i][j]=(1ll*sum[i-1][j]*(j+1)%mod-Sum[i-1][j]+mod)%mod;
			sum[i][j]=(sum[i][j-1]+dp[i][j])%mod,Sum[i][j]=(Sum[i][j-1]+1ll*dp[i][j]*j%mod)%mod;
		}
}
int ans,Ans[N][N];
inline void calc(){
	For(i,1,n) For(j,0,m-2) Ans[i][j]=(Ans[i-1][j]+dp[i][j])%mod;
	For(i,1,n) For(j,0,m-2) ans=(ans+1ll*Ans[i][j]*(m-j-1)%mod*dp[n-i+1][j]%mod)%mod;
	printf("%d\n",ans);
}
int main(){
	init(),calc();
}

#include <bits/stdc++.h>
using namespace std;
const int MOD = 1000000007;
const int NMAX = 2015;
int dp[NMAX][NMAX], ans, n, m;
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("date.in","r",stdin);
        freopen("date.out","w",stdout);
    #endif // ONLINE_JUDGE
    cin >> n >> m;
    for(int i = 1;i <= n;++i){
        long long  s1 = 0;
        long long s2 = 0;
        for(int j = 2;j <= m; ++j)
        {
            s1 += dp[i-1][j];
            s2 += 1LL*j*dp[i-1][j]%MOD;
            s1 %= MOD;s2 %= MOD;
            dp[i][j] = (1LL+(j+1)*s1-s2+MOD)%MOD;
        }
    }
    for(int i = 1;i <= n; ++i){
        long long s1 = 0;
        long long s2 = 0;
        for(int j = 2;j <= m; ++j){
            ans += 1LL*dp[i][j]*(1+(j+1)*s1%MOD-s2+MOD)%MOD*(m-j+1)%MOD;
            s1 += dp[n-i][j];   s1 %= MOD;
            s2 += 1LL*j*dp[n-i][j]; s2 %= MOD;
            ans %= MOD;
        }
    }
    cout<<ans<<"\n";
    return 0;
}

#pragma warning(disable:4786)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<functional>
#include<string>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<utility>
#include<fstream>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdio>
#include <ctime>

using namespace std;

#define MEM(a,b) memset(a,(b),sizeof(a))
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b)  ((a) < (b) ? (a) : (b))
#define istr(S) istringstream sin(S)
#define MP make_pair
#define pb push_back
#define inf 1000000000
#define   M 1000000007

#define maxn 1000000

//typedef long long  LL;
typedef __int64 LL;
typedef pair<int,int> pi;
typedef vector<int> vi;
typedef vector<string> vs;
typedef vector<double> vd;

LL f[2005][2005],g[2005][2005],h[2005][2005];
LL ff[2005][2005];
LL ga[2005][2005];
LL gb[2005][2005];

int main()
{
	int i,j,k,tests,cs=0,R,C;

	cin>>R>>C;

	if(C<2)
	{
		puts("0");
		return 0;
	}

	for(j=2;j<=C;j++)
	{
		f[1][j]=1;
		g[1][j] = (g[1][j-1]+f[1][j])%M;
		h[1][j] = (h[1][j-1]+ f[1][j]*(j-1))%M;

		ff[1][j]=1;
	}

	for(i=2;i<=R;i++)
		for(j=2;j<=C;j++)
		{
			f[i][j] = (g[i-1][j]*j - h[i-1][j])%M;
			g[i][j] = (g[i][j-1]+f[i][j])%M;
			h[i][j] = (h[i][j-1]+ f[i][j]*(j-1))%M;

			ff[i][j] = (f[i][j]-f[i-1][j])%M;

			//printf("%d %d %I64d %I64d\n",i,j,f[i][j],ff[i][j]);
		}

	LL ans=0;

	for(i=1;i<=R;i++)
	{
		LL p=0,q=0;
		for(k=2;k<=C;k++)
		{
			ga[i][k]=(ga[i-1][k] + f[i][k])%M;
			gb[i][k]=(gb[i-1][k] + ff[i][k])%M;
		}

	}

	for(i=1;i<=R;i++)
		for(k=2;k<=C;k++)
		{

			LL p= (C-k+1);
			p=(p*ga[i][k])%M;
			p=(p*gb[R-i+1][k])%M;
			ans += p;
			ans%=M;

			//	printf("%d %d %d %I64d %I64d %I64d\n",k,i,j,f[i][k],
					//ff[j][k],q);
		}

	printf("%I64d\n",ans);

	return 0;
}

/*#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")*/
#include<bits/stdc++.h>
#define ll long long
#define inf 1000000005
#define put putchar('\n')
#define F(i,a,b) for (int i=(a);i<=(b);i++)
#define D(i,a,b) for (int i=(a);i>=(b);i--)
#define go(i,t) for (int i=head[t];i;i=Next[i])
#define sqr(x) ((x)*(x))
#define re register
#define mp make_pair
#define fi first
#define se second
#define pa pair<int,int>
#define pb push_back
#define be begin()
#define en end()
#define ret return puts("-1"),0;
#define mod 1000000007
//#define N 500055
//#define int ll
using namespace std;
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline int read(){char c=getchar();int tot=1;while ((c<'0'|| c>'9')&&c!='-') c=getchar();if (c=='-'){tot=-1;c=getchar();}
int sum=0;while (c>='0'&&c<='9'){sum=sum*10+c-'0';c=getchar();}return sum*tot;}
inline void wr(int x){if (x<0) {putchar('-');wr(-x);return;}if(x>=10)wr(x/10);putchar(x%10+'0');}
inline void wrn(int x){wr(x);put;}inline void wri(int x){wr(x);putchar(' ');}
inline void wrn(int x,int y){wri(x);wrn(y);}inline void wrn(int a,int b,int c){wri(a);wrn(b,c);}
int n,m,f[2005][2005],sum[2005],g[2005][2005],num,ans;
inline void add(int &x,int k){x+=k;x-=(x>=mod)?mod:0;x+=(x<0)?mod:0;}
signed main(){
	n=read();m=read();
	//f[i][j]前i个，j长度的个数
	F(i,1,n+1){
		int t=0;
		F(j,2,m){f[i][j]=f[i][j-1];add(f[i][j],t=(t+f[i-1][j])%mod);}
		F(j,2,m) add(f[i][j],1);
	}
	F(i,1,n)
		F(j,2,m) add(ans,1LL*f[i][j]*(f[n-i+1][j]-f[n-i][j])%mod*(m-j+1)%mod);
	wrn((ans%mod+mod)%mod);
	return 0;
}

#include<bits/stdc++.h>

using namespace std;

typedef long long INT;

#define NN 2010
#define mod 1000000007

int dp[NN][NN];
int sum[NN][NN][2];

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	int n, m;
	scanf("%d %d", &n, &m);

	for(int j=2; j<=m; j++) {
		dp[1][j] = 1;
		sum[1][j][0] = j - 1;
		sum[1][j][1] = sum[1][j-1][1] + j;
	}

	for(int i=2; i<=n; i++) {
		for(int j=2; j<=m; j++) {
			dp[i][j] = (INT) sum[i-1][j][0] * (j + 1) % mod - sum[i-1][j][1] % mod;
			dp[i][j] = (dp[i][j] % mod + mod) % mod;
			sum[i][j][0] = (sum[i][j-1][0] + dp[i][j]) % mod;
			sum[i][j][1] = (sum[i][j-1][1] + (INT) dp[i][j] * j % mod) % mod;
			dp[i][j] = (dp[i][j] + dp[i-1][j]) % mod;
		}
	}

	INT tot = 0;

	for(int i=1; i<=n; i++) for(int j=2; j<=m; j++) {
		tot += (INT) dp[i][j] * dp[n-i+1][j] % mod * (m - j + 1) % mod;
		tot -= (INT) dp[i][j] * dp[n-i][j] % mod * (m - j + 1) % mod;
		tot %= mod;
	}

	tot = (tot % mod + mod) % mod;

	printf("%d\n", tot);

}

#include<cstdio>
#define int long long
using namespace std;
inline int read(){int x=0,f=1,ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}
inline void write(int x){if (x<0) putchar('-'),x=-x; if (x>=10) write(x/10); putchar(x%10+'0');}
inline void writeln(int x){write(x); puts("");}
const int N=2005,mod=1e9+7;
int n,m,dp[N][N],sum,ans;
inline void init(){
	n=read(); m=read();
}
inline void update(int &x,int y){
	x=(x+y)%mod;
}
inline void solve(){
	for (int i=1;i<=m;i++) dp[1][i]=1;
	for (int i=2;i<=n;i++){
		dp[i][1]=1; sum=0;
		for (int j=2;j<=m;j++){
			update(sum,dp[i-1][j]);
			update(dp[i][j],sum+dp[i][j-1]);
		}
	}
	for (int i=1;i<=n;i++){
		for (int j=2;j<=m;j++){ //枚举下面
			update(ans,(dp[i][j]-dp[i-1][j]+mod)%mod*dp[n-i+1][j]%mod*(m-j+1)%mod);
		}
	}
	writeln(ans);
}
signed main(){
	init(); solve();
	return 0;
}

#include <bits/stdc++.h>

using namespace std;

const int mod = 1e9+7;
int add(int a, int b) {
	return a + b < mod ? a + b : a + b - mod;
}
int mul(int a, int b) {
	return int(1LL * a * b % mod);
}

const int N = 2005;

int dp[N][N];

int f(int n, int len) {
	if(len < 2 or n < 0) return 0;
	if(n == 0) return 1;
	int &ans = dp[n][len];
	if(~ans) return ans;
	ans = f(n - 1, len);

	ans = add(ans, f(n, len - 1));
	ans = add(ans, f(n, len - 1));
	ans = add(ans, mod - f(n, len - 2));

	return ans;
}

int pref[N][N];
int pref2[N][N];

int main() {
	memset(dp, -1, sizeof dp);

	for(int i = 0; i < N; i++) {
		for(int j = 0; j < N; j++) {
			pref[i][j] = f(i, j);
			if(i > 0) pref[i][j] = add(pref[i][j], pref[i - 1][j]);
		}
	}
	for(int i = 0; i < N; i++) {
		for(int j = 0; j < N; j++) {
			if(i == 0) {
				pref2[i][j] = f(i, j);
			}
			else {
				pref2[i][j] = pref2[i - 1][j];
				pref2[i][j] = add(pref2[i][j], f(i, j - 1));
				pref2[i][j] = add(pref2[i][j], f(i, j - 1));
				pref2[i][j] = add(pref2[i][j], mod - f(i, j - 2));
			}
		}
	}

	int n, m;
	scanf("%d %d", &n, &m);

	int ans = 0;
	for(int i = 1; i <= n; i++) {
		for(int len = 2; len <= m; len++) {
			// int tmp = mul(f(n - i, len), f(i - 1, len));
			int tmp = mul(pref2[n - i][len], pref[i - 1][len]);
			tmp = mul(tmp, m - len + 1);
			ans = add(ans, tmp);
		}
	}

	printf("%d\n", ans);
}

#include<bits/stdc++.h>
using namespace std;
#define FAST ios_base::sync_with_stdio(false);cin.tie(NULL);
#define time_taken_start int begtime = clock();
#define time_taken_end int endtime = clock(); \
cerr << "\n\n" << "Time elapsed: " << \
(endtime - begtime)*1000/CLOCKS_PER_SEC << " ms\n\n"; \
return 0;
#define ll long long int
#define ull unsigned long long int
#define ld long double
#define mod 1000000007
#define inf 100000000000000007
#define eps 0.000000000001
#define pi acosl(-1)
#define pdd pair<ld,ld>
#define pll pair<ll,ll>
#define ff first
#define ss second
#define vpl vector<pll>
#define vll vector<ll>
#define mseti multiset <ll>
#define msetd multiset <ll,greater<ll>>
#define pb push_back
#define pf push_front
#define lb lower_bound
#define ub upper_bound
#define stp fixed<<setprecision(20)
#define endl '\n'
ll d[2009][2009];
void solve()
{
    ll n,m;
    cin>>n>>m;
    for(ll i=2;i<=m;i++)
    {
        d[1][i]=1;
    }
    ll sum,pre;
    for(ll i=2;i<=n;i++)
    {
        sum=0;pre=0;
        for(ll j=2;j<=m;j++)
        {
            pre+=d[i-1][j];
            pre%=mod;
            sum+=pre;
            sum%=mod;
            d[i][j]=1+sum;
            d[i][j]%=mod;
        }
    }
    ll ans=0;
    for(ll i=1;i<n;i++)
    {
        for(ll j=2;j<=m;j++)
        {
            ll x=((d[i][j]*d[n-i+1][j])%mod)*(m-j+1);
            x%=mod;
            ans+=x;
            x=((d[i][j]*d[n-i][j])%mod)*(m-j+1);
            x%=mod;
            ans-=x;
            ans%=mod;
            ans+=mod;
            ans%=mod;
        }
    }
    for(ll j=2;j<=m;j++)
    {
        ll x=d[n][j]*(m-j+1);
        x%=mod;
        ans+=x;
        ans%=mod;
    }
    cout<<ans;
}
int main()
{
    FAST
    #ifdef ayk_16
    freopen("input.txt","rt",stdin);
    freopen("output.txt","wt",stdout);
    #endif
    time_taken_start
    ll t=1;
    //cin>>t;
    for(ll i=0;i<t;i++)
    {
        //cout<<"Case #"<<i+1<<": ";
        solve();
    }
    time_taken_end
}

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long LL;

const int maxn=2010;
const LL mod=1e9+7;

void upd(int &a,int b){
	a+=b;
	if(a>=mod) a-=mod;
	if(a<0) a+=mod;
}

int f[maxn][maxn],n,m,sum1[maxn][maxn],sum2[maxn][maxn];

int main(){
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	scanf("%d%d",&n,&m);
	for(int i=2; i<=m; ++i) f[1][i]=1;
	sum1[1][2]=f[1][2];
	sum2[1][2]=f[1][2]*2;
	for(int i=3; i<=m; ++i){
		sum1[1][i]=sum1[1][i-1];
		sum2[1][i]=sum2[1][i-1];
		upd(sum1[1][i],f[1][i]);
		upd(sum2[1][i],1ll*f[1][i]*i%mod);
	}
	for(int i=2; i<=n; ++i)
		for(int j=2; j<=m; ++j){
			f[i][j]=1+1ll*sum1[i-1][j]*(j+1)%mod-sum2[i-1][j];
			f[i][j]%=mod;
			sum1[i][j]=sum1[i][j-1];
			sum2[i][j]=sum2[i][j-1];
			upd(sum1[i][j],f[i][j]);
			upd(sum2[i][j],1ll*f[i][j]*j%mod);
		}
	LL ans=0;
	for(int t=1; t<=n; ++t)
		for(int len=2; len<=m; ++len){
			ans+=1ll*f[t][len]%mod*(f[n-t+1][len]-f[n-t][len])%mod*(m-len+1)%mod;
			ans%=mod;
		}
	ans=(ans%mod+mod)%mod;
	printf("%d\n",(int)ans);
	return 0;
}

#include<stdio.h>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=2005,Mod=1000000007;
int f[N][N],g[N][N],sum,Ans,n,m;
inline int Read(){int t=0,f=1; char c=getchar();
	for (;c>57||c<48;c=getchar()) if (c=='-') f=-1;
	for (;c>47&&c<58;c=getchar()) t=(t<<1)+(t<<3)+c-48; return t*f;
}
inline int Add(int &x,int y){x=(x+y%Mod)%Mod;}
int main(){n=Read(),m=Read();
	for (int i=1;i<=n;i++,sum=0)
		for (int j=2;j<=m;j++){
			Add(f[i][j],g[i-1][j]+1);
			Add(sum,f[i][j]),Add(g[i][j],g[i][j-1]+sum);
		}
	for (int i=1;i<=n;i++)
		for (int j=2;j<=m;j++)
			Add(Ans,1ll*f[i][j]*(g[n-i][j]-f[n-i][j]+1)%Mod*(m-j+1)%Mod);
	printf("%d\n",Ans);
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <time.h>
#include <iostream>
#include <functional>
#include <numeric>
#include <algorithm>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <string>
#include <bitset>
#include <map>
#include <set>
using namespace std;
typedef long long lint;
typedef long double llf;
typedef pair<int, int> pi;
const int mod = 1e9 + 7;

int dp[2005][2005];
int n, m, s;
int main(){
	cin >> n >> m;
	s = max(n, m);
	for(int i=1; i<=s; i++){
		int ds1 = 0, ds2 = 0;
		for(int j=2; j<=s; j++){
			ds1 += dp[i-1][j];
			ds2 += 1ll * dp[i-1][j] * (j - 1) % mod;
			ds1 %= mod, ds2 %= mod;
			dp[i][j] = mod + 1 + 1ll * ds1 * j % mod - ds2;
			dp[i][j] %= mod;
		}
	}
	lint ret = 0;
	for(int i=1; i<=n; i++){
		int ds1 = 0, ds2 = 0;
		for(int j=2; j<=m; j++){
			int le = dp[i][j];
			int ri = 1 + 1ll * ds1 * j % mod + mod - ds2;
			ri %= mod;
			ds1 += dp[n-i][j];
			ds2 += 1ll * dp[n-i][j] * (j - 1) % mod;
			ds1 %= mod;
			ds2 %= mod;
			ret += (1ll * le * ri % mod) * (m - j + 1) % mod;
ret %= mod;
		}
	}
	cout << ret;
}

#include<iostream>
#include<cstdio>
using namespace std;
const int N=2001;
const int MOD=1000000007;
int n,m;
long long dp[N][N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        dp[1][i]=1;
    for(int i=2;i<=n;i++)
    {
        long long sum=0;
        dp[i][1]=1;
        for(int j=2;j<=m;j++)
            sum=(sum+dp[i-1][j])%MOD,dp[i][j]=(dp[i][j]+dp[i][j-1]+sum)%MOD;
    }
    long long ans=0;
    for(int i=1;i<=n;i++)
        for(int j=2;j<=m;j++)
            ans=(ans+(dp[i][j]-dp[i-1][j]+MOD)*dp[n-i+1][j]%MOD*(m-j+1)%MOD)%MOD;
    printf("%lld",ans);
    return 0;
}
	 	 		      	 		      		 	 			//hellobig_tq

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=2e3+5,mod=1e9+7;

int f[maxn][maxn];
int g[maxn][maxn];
int n,m,ans;

int main(){
	scanf("%d%d",&n,&m);

	for(int i=2;i<=m;i++) f[1][i]=1;
	for(int i=2;i<=n;i++){
		int sum=0;
		for(int j=2;j<=m;j++){
			sum=(sum+f[i-1][j])%mod;
			f[i][j]=(f[i][j-1]+sum)%mod;
		}
	}

	for(int i=2;i<=m;i++) g[1][i]=1;
	for(int i=2;i<=n;i++){
		int sum=0;
		for(int j=2;j<=m;j++){
			sum=(sum+f[i-1][j-1])%mod;
			g[i][j]=(g[i][j-1]+sum)%mod;
			g[i][j]=(g[i][j]+f[i-1][j-1])%mod;
		}
	}

	for(int i=2;i<=n;i++)
		for(int j=2;j<=m;j++)
			f[i][j]=(f[i][j]+f[i-1][j])%mod;

	for(int i=2;i<=n;i++)
		for(int j=2;j<=m;j++)
			g[i][j]=(g[i][j]+g[i-1][j])%mod;

	for(int i=1;i<=n;i++){
		for(int j=2;j<=m;j++){
			int x=1ll*f[i][j]*g[n-i+1][j]%mod;
			ans=(ans+1ll*x*(m-j+1)%mod)%mod;
		}
	}

	printf("%d\n",ans);
	return 0;
}

#include <bits/stdc++.h>

using namespace std;

const int MOD = 1000000007;
const int N = 2010;

int n,m,f[N][N],ans;

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,t,s;i<=n;i++){
		t=0,s=1;
		for(int j=2;j<=m;j++) t=(t+f[i-1][j])%MOD,f[i][j]=s=(s+t)%MOD;
	}
	for(int i=1;i<=n;i++)
		for(int j=2;j<=m;j++)
			ans=(ans+1ll*(m-j+1)*(f[i][j]-f[i-1][j])%MOD*f[n-i+1][j])%MOD;
	printf("%d\n",(ans+MOD)%MOD);
	return 0;
}

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
#define LL long long
#define MOD 1000000007
#define inf 2000000000LL
#define Key_value ch[ch[root][1]][0]
using namespace std;
LL f[2005][2005],g[2005][2005];
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        LL sum=0;
        for(int j=2;j<=m;j++){
            f[i][j]=(f[i][j]+g[i-1][j]+1)%MOD;
            sum=(sum+f[i][j])%MOD;
            g[i][j]=(g[i][j]+g[i][j-1]+sum)%MOD;
        }
    }
    LL ans=0;
    for(int i=1;i<=n;i++){
        for(int j=2;j<=m;j++){
            ans=(ans+((LL)f[i][j]*(m-j+1)%MOD)*(g[n-i][j]-f[n-i][j]+1)%MOD)%MOD;
        }
    }
    cout<<ans<<endl;
    return 0;
}

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define rep(i,l,r) for(int i = l;i <= r;++ i)
#define Add(a,b) (a + b >= Mod ? a + b - Mod : a + b)
using namespace std;
typedef long long ll;
const int Mod = 1000000007;
int n,m;
ll f[3003][3003],sum,ssum,ans = 0;
int main()
{
    scanf("%d%d",&n,&m);
	rep(i,2,m) f[1][i] = 1;
	rep(i,2,n){
	   sum = ssum = 0;
	   rep(j,1,m){
	      sum = Add(sum,f[i - 1][j]);
		  ssum = Add(ssum,sum);
		  f[i][j] = Add(f[i][j],ssum);// f[i][j] = f[i - 1][1] * j + ... f[i - 1][j] * 1;
	   }
	}
	rep(i,2,n)
	 rep(j,1,m)
	    f[i][j] = Add(f[i][j],f[i - 1][j]);
	rep(i,1,n)
	 rep(j,1,m)
	   ans = Add(ans,f[i][j] * f[n - i + 1][j] % Mod * (m - j + 1) % Mod);
	rep(i,1,n - 1)
	 rep(j,1,m)
	   ans = (ans - f[i][j] * f[n - i][j] % Mod * (m - j + 1) % Mod) % Mod;
	cout<<ans<<endl;
	return 0;
}

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define fi "CF179_1_4.INP"
#define fo "CF179_1_4.OUT"
#define nmax 2000+5
#define INF 1000000000
using namespace std;
typedef long long ll;
const ll mod=ll(1000000007);
//VARIABLES
int m,n;
ll f[nmax][nmax],g[nmax][nmax],S,res;
//FUNCTION PROTOTYPES

void Process();

//MAIN
int main()
{
//       freopen(fi,"r",stdin);
//       freopen(fo,"w",stdout);
       Process();
       return 0;
}

//FUNCTIONS AND PROCEDURES
void Process()
{
	scanf("%d%d",&m,&n);
	for (int j=2;j<=n;++j) f[1][j]=g[1][j]=1;
	for (int i=2;i<=m;++i)
	{
		for (int j=2;j<=n;++j)
		{
			f[i][j]=(f[i-1][j]+f[i][j-1]*2ll-f[i][j-2]+mod)%mod;
			g[i][j]=(f[i][j-1]*2ll-f[i][j-2]+mod)%mod;
		}
	}
	for (int i=1;i<=m;++i)
	for (int j=2;j<=n;++j)
	{
		f[i][j]=(f[i][j]+f[i-1][j])%mod;
		g[i][j]=(g[i][j]+g[i-1][j])%mod;
	}
//	for (int i=1;i<=m;++i)
//	for (int j=2;j<=n;++j)
//	cout << i << " " << j << "   " << f[i][j] << endl;
	for (int i=1;i<=m;++i)
	for (int j=2;j<=n;++j)
	{
		S=ll(n-j+1);
		S=(S*f[i][j]*g[m-i+1][j])%mod;
		res=(res+S)%mod;
	}
	cout << res << endl;
}

// I'm Fine ...
// I'm used to it :-(
#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;

/** +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ **/

#define ios                 ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL)
#define Time()              cerr << clock() * 1000 / CLOCKS_PER_SEC << "ms\n"
#define show(x)             cerr << #x << " = " << (x) << '\n'
#define pob                 pop_back
#define pb                  push_back
#define m_p                 make_pair
#define inf                 1061109567
#define clMAXN              const int MAXN
#define F                   first
#define S                   second
#define int                 ll

/** +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ **/

typedef long long                       ll;
typedef long double                     ld;
// typedef pair<ll, ll>                    pll;
// typedef long long int                   lli;
typedef pair<int, int>                  pii;
// typedef unsigned long long int          ull;

/** +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ **/

//template<typename T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;
template<typename T, typename L> bool smax(T &x, L y) { return x < y ? (x = y, true) : false; }
template<typename T, typename L> bool smin(T &x, L y) { return y < x ? (x = y, true) : false; }

/** +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ **/

clMAXN = 3192;
const int mod = 1e9 + 7;
int n, m;
int c[MAXN << 1][MAXN];
int dp[MAXN][MAXN];
int ans;

/** +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ **/

int32_t main() {
    cin >> n >> m;
    for (int i = 0; i < MAXN; i++)
        for (int j = 0; j <= i; j++) {
            if (j == 0) {
                c[i][j] = 1;
                continue;
            }
            c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
        }
    for (int w = 1; w <= m; w++)
        for (int h = 0; h < n; h++)
            dp[w][h] = (c[(h << 1) + (w - 1)][w - 1] + (h ? dp[w][h - 1] : 0)) % mod;
    for (int w = 1; w <= m; w++)
        for (int h = 0; h < n; h++)
            ans = (ans + ((ll)((m - w) * c[(h << 1) + (w - 1)][w - 1]) % mod) * (ll)(dp[w][n - h - 1])) % mod;
    return cout << ans << '\n', false;
}

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<set>
#define LL long long
#define fi first
#define se second
#define MP make_pair
#define PII pair<int,int>
using namespace std;
int n,m;
LL P=1e9+7,f[2010][2010],s1[2010][2010],s2[2010][2010],g[2010][2010];
void read(int &x)
{
	char ch=getchar();int mark=1;for(;ch!='-'&&(ch<'0'||ch>'9');ch=getchar());if (ch=='-') mark=-1,ch=getchar();
	for(x=0;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-48;x*=mark;
}
int main()
{
	read(n);read(m);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			s1[i][j]=(s1[i][j-1]+f[i-1][j])%P;
			s2[i][j]=(s2[i][j-1]+(LL)f[i-1][j]*j%P)%P;
		}
		for(int j=2;j<=m;j++) f[i][j]=((LL)s1[i][j]*(j+1)%P-s2[i][j]+1)%P;
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			s1[i][j]=(s1[i][j-1]+f[i][j])%P;
			s2[i][j]=(s2[i][j-1]+(LL)f[i][j]*j%P)%P;
			g[i][j]=((LL)s1[i][j-1]*(j+1)%P-s2[i][j-1])%P;
		}
	}
	LL ans=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) (ans+=(LL)((LL)f[i][j]*(g[n-i][j]+1)%P)*(m-j+1)%P)%P;
	ans=(ans+P)%P;
	printf("%I64d\n",ans);
	return 0;
}

#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

namespace IO {
static const int kMaxSize = 1 << 20;
char buf[kMaxSize], *S = buf, *T = buf;
bool neg;
inline bool Fetch() { return T = (S = buf) + fread(buf, 1, kMaxSize, stdin), S != T; }
inline char NC() { return S == T ? (Fetch() ? *S++ : EOF) : *S++; }
template <typename Int> inline void RI(Int &x) {
  x = neg = 0;
  char ch = NC();
  for (; isspace(ch); ch = NC())
    ;
  if (ch == '-')
    neg = true, ch = NC();
  for (; isdigit(ch); ch = NC())
    x = x * 10 + ch - '0';
  if (neg) x = -x;
}
inline char RC() {
  char ch;
  for (ch = NC(); isspace(ch); ch = NC())
    ;
  return ch;
}
inline int RS(char *s) {
  int cur = 0, ch = NC();
  for (; isspace(ch); ch = NC());
  for (; ch != EOF && !isspace(ch); ch = NC())
    s[cur++] = ch;
  return s[cur] = 0, cur;
}
} // namespace IO

using IO::RI;
using IO::RS;
using IO::RC;

const int kMaxN = 2005, kMod = 1e9 + 7;
ll n, m, f[kMaxN][kMaxN];

int main() {
  RI(n), RI(m);
  for (int i = 1; i <= m; ++i) {
    f[1][i] = 1;
  }
  for (int i = 2, sum = 0; i <= n; ++i, sum = 0) {
    f[i][1] = 1;
    for (int j = 2; j <= m; ++j) {
      sum = (sum + f[i - 1][j]) % kMod;
      f[i][j] = (f[i][j - 1] + sum) % kMod;
    }
  }
  ll ans = 0;
  for (int i = 1; i <= n; ++i) {
    for (int j = 2; j <= m; ++j) {
      ans = (ans + (1LL * (m - j + 1) * (f[i][j] - f[i - 1][j])) % kMod * f[n - i + 1][j] % kMod) % kMod;
    }
  }
  printf("%lld\n", ans);
  return 0;
}

//$UANAS$
#include<bits/stdc++.h>

using namespace std;

#define int long long
#define rep(i,f,l) for(int i=f;i<l;++i)
#define FOR(i,n) for(int i=0;i<n;++i)
#define sim template < class c
#define ris return * this
#define imie(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "
#define Foreach(i, x) for (__typeof(x.begin()) i = x.begin(); i != x.end(); i++)
#define pb push_back
#define SI size()
#define S second
#define F first
#define C clear()
#define pii pair<int,int>
#define B begin()
#define mp make_pair
#define E end()
#define I insert
#define piii pair<long long,pair<long long,long long> >
#define P push
#define T top()
#define PP pop()

const int MAXn=2e3+10;
const int MOD=1e7+9;
int n,m,s[MAXn],dp[MAXn][MAXn],a[MAXn],ans;

signed main(){

    cin>>n>>m;
    rep(i,1,n+1){

        dp[2][i]=i;
        s[i+1]+=i;
        a[i+1]+=i;
    }
    rep(i,3,m+1){
        rep(j,1,n+1){

            s[j]+=dp[i][j-1];
            s[j]%=MOD;
            a[j]+=s[j];
            a[j]%=MOD;
            dp[i][j]=(a[j]+1)%MOD;
        }
    }
    rep(i,1,n+1){
        rep(j,2,m+1){
            int x=
                    (dp[j][i]*(dp[j][n-i+1]-dp[j][n-i]+MOD))%MOD;
            x=(x*(m+1-j))%MOD;
            ans+=x;
            ans%=MOD;
        }
    }
    return
            cout<<ans<<endl,0;
}

#include <iostream>
#include <cstdio>

#include <queue>
#include <cstring>

using namespace std;

#define FILE_NAME "io"

const int MAXSIZE = 2001;
const long long BASE = 1000000007;

int n, m;

long long dp[MAXSIZE + 1][MAXSIZE + 1];
long long sum[MAXSIZE + 1][MAXSIZE + 1];

long long pow (int x, int n) {
    if (n == 0) return 1;

    long long res = pow (x, n >> 1);
    res *= res;
    if (n & 1) res *= x;
    return res;
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen (FILE_NAME".in", "r", stdin);
    freopen (FILE_NAME".out", "w", stdout);
    #endif // ONLINE_JUDGE

    scanf ("%d%d", &n, &m);

    for (int l = 1; l < m; l++)
        dp[1][l] = 1;

    for (int i = 2; i <= n; i++) {
        long long sum = 0;
        for (int j = 1; j < m; j++) {
            sum += (dp[i - 1][j]) % BASE;
            dp[i][j] = (dp[i][j - 1] + sum) % BASE;
        }
    }

    for (int j = 1; j < m; j++)
        for (int t = n - 1; t >= 1; t--)
            sum[n - t][j] = (sum[n - t - 1][j] + dp[n - t][j]) % BASE;

    long long ANS = 0;
    for (int t = 1; t <= n; t++) {
        for (int j = 1; j < m; j++) {
            long long count = 0;

            count += sum[n - t][j];
            count -= dp[n - t + 1][j] * (n - t);
            count += (dp[n - t + 1][j] - dp[0][j]) * (n - t + 1);

            count %= BASE;

            ANS = (ANS + dp[t][j] * (m - j) * count) % BASE;
        }
    }

    printf ("%I64d", ANS);

    return 0;
}

#include <iostream>
#define MAXN 2005
#define MOD 1000000007

using namespace std;

int n, m;
long long res, c[MAXN][MAXN];

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

  long long p, q, s;
  for (int i = 1; i <= n; i++)
  {
    p = 1, q = 0;
    for (int j = 2; j <= m; j++)
    {
      q = (q + c[i - 1][j]) % MOD;
      p = (p + q) % MOD;
      c[i][j] = p;
    }
  }

  res = 0;
  for (int i = 1; i <= n; i++)
  {
    p = 1; q = 0;
    for (int j = 2; j <= m; j++)
    {
      s = m - j + 1;
      p = (p + q) % MOD;
      q = (q + c[n - i][j]) % MOD;
      res = (res + s * (c[i][j] * p % MOD)) % MOD;
      p = (p + c[n - i][j]) % MOD;
    }

    if (i == 1 || i == n)
      for (int j = 2; j <= m; j++)
      {
        s = m - j + 1;
        res = (res + s * c[n][j]) % MOD;
      }
  }

  cout << res;

//  system("pause");
}

/*
 * if you are interested in the reference code here,
 * see https://github.com/georeth/OJLIBS for more information
 *
 * Solution Author : Georeth Chow <georeth2010@gmail.com>
 */
#include <cstdio>
#include <cmath>
#include <climits>      // INT_MIN LLONG_MIN
#include <cstring>      // memset
#include <cstdlib>      // malloc
#include <cstdint>      // int64_t
#include <cinttypes>    // PRId64 SCNd64
#include <cassert>      // assert
#include <limits>       // numeric_limits
#include <vector>
#include <deque>
#include <map>
#include <set>
#include <tuple>        // pair, tuple
#include <iostream>     // be careful.
                        // mix with cstdio: slowwww...
                        // mix with cstdio + fastio: bug
#include <sstream>
#include <algorithm>
#include <utility>
#include <iterator>
template <typename It>
struct iter_range : std::pair<It, It> {
    typedef std::pair<It, It> base_t;
    typedef It iterator;
    using base_t::base_t;
    It begin() { return base_t::first; }
    It end() { return base_t::second; }
};
template <typename It>
iter_range<std::reverse_iterator<It>> rev(const iter_range<It> &origin) {
    using rev_t = std::reverse_iterator<It>;
    return {rev_t(origin.second), rev_t(origin.first)};
}
// TODO: rev on std::string, etc.
template <typename Int = int>
struct int_iter {
    Int i;
    explicit int_iter(Int i = 0) : i(i) { }
    Int operator*() const { return i; }
    int_iter &operator++() { ++i; return *this; }
    int_iter &operator--() { --i; return *this; }
    int_iter operator+(Int step) const { return int_iter(i + step); }
    int_iter operator-(Int step) const { return int_iter(i - step); }
    Int operator-(const int_iter &that) const { return i - that.i; }
    int_iter &operator+=(Int step) { i += step; return *this; }
    int_iter &operator-=(Int step) { i -= step; return *this; }
    bool operator==(const int_iter &that) const { return  i == that.i; }
    bool operator!=(const int_iter &that) const { return !(*this == that); }
    Int operator[](Int n) { return i + n; }
    typedef Int difference_type;
    typedef Int value_type;
    typedef Int *pointer;
    typedef Int reference; // not a int container, never reference to int
    typedef std::random_access_iterator_tag iterator_category;
};
template <typename Int = int>
using int_range = iter_range<int_iter<Int>>;
template <typename Int>
int_range<Int> range(Int b, Int e) { return {int_iter<Int>(b), int_iter<Int>(e > b ? e : b)}; }
template <typename Int>
int_range<Int> range(Int n) { return range(Int(), n); }
template <typename Int>
int_range<Int> nrange(Int n) { return range(Int(1), Int(n+1)); }
template <typename Int>
int_range<Int> inrange(Int b, Int e) { return range(b, Int(e + 1)); }
using namespace std;    // use as solution header. name polution is fine.
#ifdef LOCAL_JUDGE
#  define pr_debug(...) fprintf(stderr, __VA_ARGS__)
#  define pr_line() fprintf(stderr, "%s: %d\n", __FILE__, __LINE__)
#else
#  define pr_debug(...)
#  define pr_line()
#endif
template <typename T>
bool chmax(T &m, const T &v) { if (v > m) return m = v, true; return false; }
template <typename T>
bool chmin(T &m, const T &v) { if (v < m) return m = v, true; return false; }
template <typename T>
T max_s(const T &v) { return v; }
template <typename T, typename... Args>
T max_s(const T &v1, const T &v2, Args... arg) {
    return max_s(max(v1, v2), arg...);
}
template <typename T>
T min_s(const T &v) { return v; }
template <typename T, typename... Args>
T min_s(const T &v1, const T &v2, Args... arg) {
    return min_s(min(v1, v2), arg...);
}
static const int HMAX32 = INT32_MAX / 2;
static const int64_t HMAX64 = INT64_MAX / 2;
#define fast_io\
    ios_base::sync_with_stdio(false); cin.tie(nullptr)
stringstream line_stream() {
    string str;
    getline(cin, str);
    return stringstream(str);
}
#define read_int(id) scanf("%d", &id)
#define read_int64(id) scanf("%" PRId64, &id)
#define new_int(id) int id; read_int(id)
#define new_int64(id) int64_t id; read_int64(id)
#define ALL(x) begin(x), end(x)
#include <type_traits>
// TODO : use gcc arith extension like __builtin_add_overflow
// try binary gcd on large number
template <typename Int>
Int gcd(Int a, Int b) {
    while (a != 0) {
        b %= a;
        if (b == 0)
            return a;
        a %= b;
    }
    return b;
}
template <typename Int, typename RInt = Int>
Int lcm(Int a, Int b) {
    return a / gcd(a, b) * static_cast<RInt>(b);
}
template <typename Int, typename XInt>
Int extended_gcd(Int a, Int b, XInt &x, XInt &y) {
    static_assert(std::numeric_limits<XInt>::is_signed,
            "x, y must be signed");
    // pre condition : a != 0 || b != 0
    // post condition : a * x + b * y = g
    // (a * x) or (b * y) may overflow, but the condition
    //                 always holds.
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    /**
     * r = a - b * q
     * b * k1 + r * k2 = g
     * => a * k2 + b * (k1 - q * k2)
     *                 x = k2
     *                 y = k1 - q * k2 = k1 - q * x
     */
    Int g = extended_gcd(b, a % b, y, x);
    y -= (a / b) * x;
    return g;
}
template <typename Int, typename TInt = int64_t>
Int mul_mod(Int a, Int b, Int m) {
    TInt p = a;
    p = (p * b) % m;
    return (Int)p;
}
template <typename Int, typename PInt, typename TInt = int64_t>
Int pow_mod(Int a, PInt p, Int m) {
    Int r;
    a %= m;
    for (r = 1; p; p >>= 1) {
        if (p & 1) r = mul_mod(r, a, m);
        a = mul_mod(a, a, m);
    }
    return r;
}
template <typename Int,
          typename XInt = typename std::make_signed<Int>::type>
Int inv_mod(Int a, Int m) {
    // a * x = gcd(a, m) (mod m)
    XInt x, y;
    extended_gcd(a, m, x, y);
    if (x < 0)
        return x + m;
    return x;
}
template <typename Int>
static Int addx_mod(Int u, Int v, Int m) {
    Int r = u + v;
    if (r >= m) r -= m;
    return r;
}
template <typename Int>
static Int subx_mod(Int u, Int v, Int m) {
    Int r = u - v;
    if (r < 0) r += m;
    return r;
}
template <typename Int>
Int div_pos_r(Int a, Int b, Int &r) {
    // 3 / 2  = 1 .. 1 (ok)
    // 3 / -2 = -1 .. 1 (ok)
    // -3 / 2 = -1 .. -1 (not ok)
    // -3 / -2 = 1 .. -1 (not ok)
    // a = q b + r
    //   = (q + 1) b + (r - b)
    //   = (q - 1) b + (r + b)
    Int q = a / b;
    r = a % b;
    if (r < 0) {
        if (b < 0)
            q += 1, r -= b;
        else
            q -= 1, r += b;
    }
    return q;
}
// TODO: gauss_factorial, factorial_mod.
//       log, factorial_exp
#define INV_MOD(x)      inv_mod((x), MOD)
#define MUL_MOD(x, y)   mul_mod((x), (y), MOD)
#define MULM_MOD(x, y)  (x) = mul_mod((x), (y), MOD)
#define POW_MOD(x, y)   pow_mod((x), (y), MOD)
#define ADDX_MOD(x, y)  addx_mod((x), (y), MOD)
#define ADDM_MOD(x, y)  (x) = addx_mod((x), (y), MOD)
#define SUBX_MOD(x, y)  subx_mod((x), (y), MOD)
#define SUBM_MOD(x, y)  (x) = subx_mod((x), (y), MOD)
// warning : mod is LARGE enough PRIME
// O(n) build
// O(1) query
struct factorial_list {
    std::vector<int> fact;
    std::vector<int> inv;
    std::vector<int> inv_fact;
    int mod;
    factorial_list(int n, int mod) : mod(mod) {
        fact.resize(n + 1);
        inv.resize(n + 1);
        inv_fact.resize(n + 1);
        fact[0] = 1;
        for (int i = 1; i <= n; ++i)
            fact[i] = mul_mod(fact[i - 1], i, mod);
        // magic: O(n) build inv[]
        // (MOD / i) * i + (MOD % i) = 0 (mod MOD)
        // (MOD % i) = -i * (MOD / i)
        // inv[i] = -MOD / i * inv[MOD % i];
        inv[1] = 1;
        for (int i = 2; i <= n; ++i) // start from 2
            inv[i] = mod - mul_mod(mod / i, inv[mod % i], mod);
        inv_fact[0] = 1;
        for (int i = 1; i <= n; ++i)
            inv_fact[i] = mul_mod(inv_fact[i - 1], inv[i], mod);
    }
    int operator()(int n) { return fact[n]; }
    int A(int n, int m) {
        return mul_mod(fact[n], inv_fact[n - m], mod);
    }
    int C(int n, int m) {
        if (m > n || n < 0 || m < 0) return 0;
        return mul_mod(A(n, m), inv_fact[m], mod);
    }
    int H(int n, int m) {
        return C(n + m - 1, m);
    }
};
// C(n, m) = C(n, n - m)
// Be cautious about overflow
// try Lucas if n is large, but r is small
// e.g C(10^15, 10^4, 1e9 + 7)
/* =====  SOLUTION START  ===== */
static const int MOD = 1000000007;
factorial_list F(5005, MOD);
int down[2005][2005]; // down[w][h] = { x1 >= x2 >= ... >= xh, x1 = w }
int downh[2005][2005]; // downh[w][h] = { x1 >= x2 >= ... >= xk, x1 = w, k <= h } = down[w][<=h]
int uph[2005][2005]; // uph[w][h] = { x0 > x1 >= x2 >= ... >= xk, x0 = w, k <= h }
                     //           = downh[w][h+1] - downh[w][h]
int main() {
    new_int(n);
    new_int(m);
    for (int w : inrange(1, m - 1))
        for (int h : inrange(1, n))
            down[w][h] = F.H(2 * h - 1, w - 1);
    for (int w : inrange(1, m - 1))
        for (int h : inrange(0, n))
            downh[w][h] = ADDX_MOD(h == 0 ? 0 : downh[w][h - 1], down[w][h]);
    for (int w : inrange(1, m - 1))
        for (int h : inrange(1, n))
            uph[w][h] = SUBX_MOD(downh[w][h+1], downh[w][h]);
    for (int w : inrange(1, m - 1))
        uph[w][0] = 1;
    int ans = 0;
    for (int t : inrange(1, n)) {
        for (int w : inrange(1, m - 1)) {
            int tmp = MUL_MOD(downh[w][n - t + 1],
                              uph[w][t - 1]);
            pr_debug("t=%d w=%d => %d\n", t, w, tmp);
            pr_debug("downh[%d][%d] = %d\n", w, n - t + 1, downh[w][n - t + 1]);
            pr_debug("uph[%d][%d] = %d\n", w, t - 1, uph[w][t - 1]);
            ADDM_MOD(ans, MUL_MOD(tmp, m - w));
        }
    }
    printf("%d\n", ans);
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
typedef signed long long ll;

#undef _P
#define _P(...) (void)printf(__VA_ARGS__)
#define FOR(x,to) for(x=0;x<to;x++)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define ZERO(a) memset(a,0,sizeof(a))
#define MINUS(a) memset(a,0xff,sizeof(a))
//-------------------------------------------------------

int N,M;
ll mo=1000000007;

ll dp[2002][2002],dp2[2002][2002],dp3[2002][2002];

void solve() {
    int i,j,k,l,r,x,y; string s;

    cin>>N>>M;

    for(x=2;x<=2000;x++) dp[x][0]=dp2[x][0]=dp3[x][0]=1;
    for(y=1;y<=2000;y++) {
        ll tot=0;
        for(x=2;x<=2000;x++) {
            tot+=dp[x][y-1];
            dp[x][y]=(dp[x-1][y]+tot)%mo;
            dp2[x][y]=(dp[x][y]+mo-dp[x][y-1])%mo;
            dp3[x][y]=(dp3[x][y-1]+dp2[x][y])%mo;
        }
    }

    int y1,y2,w;
    ll ret=0;
    FOR(y1,N) for(y2=y1;y2<N;y2++) {
        for(w=2;w<=M;w++) ret+=dp3[w][y1]*dp3[w][N-1-y2]*(M+1-w);
    }
    cout << ret << endl;
}

int main(int argc,char** argv){
    string s;int i;
    if(argc==1) ios::sync_with_stdio(false);
    FOR(i,argc-1) s+=argv[i+1],s+='\n';
    FOR(i,s.size()) ungetc(s[s.size()-1-i],stdin);
    solve(); return 0;
}

#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

namespace IO {
static const int kMaxSize = 1 << 20;
char buf[kMaxSize], *S = buf, *T = buf;
bool neg;
inline bool Fetch() { return T = (S = buf) + fread(buf, 1, kMaxSize, stdin), S != T; }
inline char NC() { return S == T ? (Fetch() ? *S++ : EOF) : *S++; }
template <typename Int> inline void RI(Int &x) {
  x = neg = 0;
  char ch = NC();
  for (; isspace(ch); ch = NC())
    ;
  if (ch == '-')
    neg = true, ch = NC();
  for (; isdigit(ch); ch = NC())
    x = x * 10 + ch - '0';
  if (neg) x = -x;
}
inline char RC() {
  char ch;
  for (ch = NC(); isspace(ch); ch = NC())
    ;
  return ch;
}
inline int RS(char *s) {
  int cur = 0, ch = NC();
  for (; isspace(ch); ch = NC());
  for (; ch != EOF && !isspace(ch); ch = NC())
    s[cur++] = ch;
  return s[cur] = 0, cur;
}
} // namespace IO

using IO::RI;
using IO::RS;
using IO::RC;

const int kMaxN = 2005, kMod = 1e9 + 7;
int n, m, f[kMaxN][kMaxN];

int main() {
  RI(n), RI(m);
  for (int i = 1; i <= m; ++i) {
    f[1][i] = 1;
  }
  for (int i = 2, sum = 0; i <= n; ++i, sum = 0) {
    f[i][1] = 1;
    for (int j = 2; j <= m; ++j) {
      sum = (sum + f[i - 1][j]) % kMod;
      f[i][j] = (f[i][j - 1] + sum) % kMod;
    }
  }
  ll ans = 0;
  for (int i = 1; i <= n; ++i) {
    for (int j = 2; j <= m; ++j) {
      ans = (ans + (m - j + 1) * (f[i][j] - f[i - 1][j]) % kMod * f[n - i + 1][j]) % kMod;
    }
  }
  printf("%lld\n", ans);
  return 0;
}

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=2005,MD=1000000007;
int f[N][N],g[N][N];
//f[i][j]表示前i行第i行j个的方案数 g[i][j]表示前i行第i行小于等于j个的方案数
void add(int &x,int y)
{
      x+=y;
      if(x>=MD) x-=MD;
}
int main()
{
      int i,j,n,m;
      scanf("%d%d",&n,&m);
      for(i=1;i<=n;++i)
      {
         int sum=0;
         for(j=2;j<=m;++j)
         {
            add(f[i][j],g[i-1][j]+1);//上一行为空
            add(sum,f[i][j]);
            add(g[i][j],g[i][j-1]+sum);
         }
      }
      int ans=0;
      for(i=1;i<=n;++i)
      {
        for(j=2;j<=m;++j)
         ans+=(long long)f[i][j]*(g[n-i][j]-f[n-i][j]+1)%MD*(m-j+1)%MD;
        ans%MD;
        //枚举最长行
      }
      printf("%d",ans%MD);
     // system("pause");
      return 0;
}

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<set>
#define LL long long
#define fi first
#define se second
#define MP make_pair
#define PII pair<int,int>
using namespace std;
int n,m,P=1e9+7,f[2010][2010],s1[2010][2010],s2[2010][2010],g[2010][2010];
void read(int &x)
{
	char ch=getchar();int mark=1;for(;ch!='-'&&(ch<'0'||ch>'9');ch=getchar());if (ch=='-') mark=-1,ch=getchar();
	for(x=0;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-48;x*=mark;
}
int main()
{
	read(n);read(m);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			s1[i][j]=(s1[i][j-1]+f[i-1][j])%P;
			s2[i][j]=(s2[i][j-1]+(LL)f[i-1][j]*j%P)%P;
		}
		for(int j=2;j<=m;j++) f[i][j]=((LL)s1[i][j]*(j+1)%P-s2[i][j]+1)%P;
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			s1[i][j]=(s1[i][j-1]+f[i][j])%P;
			s2[i][j]=(s2[i][j-1]+(LL)f[i][j]*j%P)%P;
			g[i][j]=((LL)s1[i][j-1]*(j+1)%P-s2[i][j-1])%P;
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) (ans+=(LL)((LL)f[i][j]*(g[n-i][j]+1)%P)*(m-j+1)%P)%P;
	ans=(ans+P)%P;
	printf("%d\n",ans);
	return 0;
}

#include <bits/stdc++.h>
#define endl '\n'

using namespace std;
struct custom_hash
{
    static unsigned long long splitmix64(unsigned long long x)
    {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(unsigned long long x) const
    {
        static const unsigned long long FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
mt19937 random_generator(chrono::steady_clock::now().time_since_epoch().count());

const int maxn = 2003;
const int mod = 1e9 + 7;

int n, m;
void read()
{
	cin >> n >> m;
}

int add(int a, int b)
{
	a += b;
	if (a >= mod)
	a -= mod;

	return a;
}

int dp[maxn][maxn];
int incr[maxn][maxn];
int pr_sum[maxn][maxn];
int f1[maxn][maxn], f2[maxn][maxn];
void solve()
{
	if (m == 1)
	{
		cout << 0 << endl;
		return;
	}

	for (int i = 2; i <= m; i++)
	incr[1][i] = 1, pr_sum[1][i] = add(pr_sum[1][i-1], incr[1][i]);

	for (int i = 2; i <= n; i++)
	for (int j = 2; j <= m; j++)
	{
		incr[i][j] = add(incr[i][j-1], pr_sum[i-1][j]);
	    pr_sum[i][j] = add(pr_sum[i][j-1], incr[i][j]);
	}

	for (int i = 1; i <= n; i++)
	for (int j = 2; j <= m; j++)
	f1[i][j] = add(f1[i][j-1], pr_sum[i][j]);

	for (int i = 1; i <= n; i++)
	for (int j = 2; j <= m; j++)
	f2[i][j] = add(f1[i][j], mod - incr[i][j]);

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

	for (int i = 2; i <= n; i++)
	{
		int sum1 = 0, sum2 = 0;
		for (int j = m; j >= 2; j--)
	    {
		   dp[i][j] = f2[i-1][j] * (m - j + 1) % mod;

		   sum2 = add(sum2, dp[i-1][j]);
		   sum1 = add(sum1, sum2);

		   dp[i][j] = add(dp[i][j], sum1);
	    }
	}

	int ans = 0;
	for (int i = 1; i <= n; i++)
	for (int j = 2; j <= m; j++)
	ans = add(ans, 1ll * dp[i][j] * (n - i + 1) % mod);

	cout << ans << endl;
}

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);

	read();
	solve();
}

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <cmath>
#include <cstring>
#include <string>
#include <iostream>
#include <complex>
#include <sstream>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
typedef vector<int> VI;
typedef pair<int,int> PII;

#define REP(i,n) for(int i=0;i<(n);++i)
#define SIZE(c) ((int)((c).size()))
#define FOR(i,a,b) for (int i=(a); i<(b); ++i)
#define FOREACH(i,x) for (__typeof((x).begin()) i=(x).begin(); i!=(x).end(); ++i)
#define FORD(i,a,b) for (int i=(a)-1; i>=(b); --i)
#define ALL(v) (v).begin(), (v).end()

#define pb push_back
#define mp make_pair
#define st first
#define nd second

#define V(a,b,c) (100 * a + 2 * b + c)

int MOD = 1000000007;
const int MAXN = 2005;

int DP[MAXN][MAXN], DP0[MAXN][MAXN];

int main() {
    int N,M;
    scanf("%d%d",&N,&M);

    if (M == 1) {
        printf("0\n");
        return 0;
    }

    REP(i,M)DP[0][i] = 1;
    FOR(i,1,N+1) {
        DP0[i-1][0] = DP[i-1][0];
        FOR(j,1,M+5) DP0[i-1][j] = (DP[i-1][j] + DP0[i-1][j-1]) % MOD;

        DP[i][0] = i + 1;
        FOR(j,1,M+5) DP[i][j] = (DP[i][j-1] + DP0[i-1][j]) % MOD;
    }

    LL result = 0;
    REP(t,N) {
        REP(w,M-1) {
            LL tmp0 = (M-1 - w) * DP[t][w] % MOD;
            LL tmp1 = DP[N-1-t][w];
            if (N-1-t != 0) tmp1 -= DP[N-1-t-1][w];
            result += tmp0 * tmp1 % MOD;
        }
    }

    result %= MOD;
    result += MOD;
    result %= MOD;

    printf("%d\n", (int)result);
}

#include <bits/stdc++.h>
#define endl '\n'

using namespace std;
struct custom_hash
{
    static unsigned long long splitmix64(unsigned long long x)
    {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(unsigned long long x) const
    {
        static const unsigned long long FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
mt19937 random_generator(chrono::steady_clock::now().time_since_epoch().count());

const int maxn = 2003;
const int mod = 1e9 + 7;

int n, m;
void read()
{
	cin >> n >> m;
}

int add(int a, int b)
{
	a += b;
	if (a >= mod)
	a -= mod;

	return a;
}

int dp[maxn][maxn];
int incr[maxn][maxn];
void solve()
{
	if (m == 1)
	{
		cout << 0 << endl;
		return;
	}

	for (int i = 2; i <= m; i++)
	incr[1][i] = 1;

	for (int i = 2; i <= n; i++)
	for (int j = 2; j <= m; j++)
	for (int k = 2; k <= j; k++)
	incr[i][j] = add(incr[i][j], 1ll * incr[i-1][k] * (j - k + 1));

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

	for (int i = 2; i <= n; i++)
	for (int j = 2; j <= m; j++)
	{
		for (int t = 1; t <= i; t++)
		{
			int first = 1;
			if (t != 1)
			{
				first = 0;
				for (int p = 2; p <= j; p++)
				first = add(first, 1ll * (j - p + 1) * incr[t-1][p] % mod);
			}

			int second = 1;
			if (t != i)
			{
				second = 0;
				for (int p = 2; p < j; p++)
				second = add(second, 1ll * (j - p + 1) * incr[i-t][p] % mod);
			}

			dp[i][j] = add(dp[i][j], 1ll * first * second % mod);
		}

	}

	int ans = 0;
	for (int i = 1; i <= n; i++)
	{
		int curr = 0;
		for (int j = 2; j <= m; j++)
		curr = add(curr, 1ll * (m - j + 1) * dp[i][j] % mod);

		ans = add(ans, 1ll * (n - i + 1) * curr % mod);
	}

	cout << ans << endl;
}

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);

	read();
	solve();
}

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define mod 1000000007
#define N 2005
using namespace std;
ll dp[N][N];
int n,m;
ll ans=0;
int main(){
 scanf("%d%d",&n,&m);
 for(int i=1;i<=m;i++)dp[1][i]=1;
 for(int i=2;i<=n;i++)
 {int sum=0;
 dp[i][1]=1;
 for(int r=2;r<=m;r++)
 sum+=dp[i-1][r],sum%=mod,dp[i][r]=(dp[i][r-1]+sum)%mod;
 }
 for(int i=1;i<=n;i++)
 for(int r=2;r<=m;r++)
 ans=(ans+((dp[i][r]-dp[i-1][r])*dp[n-i+1][r]%mod)*(m-r+1))%mod;
 cout<<ans;
}

#include<stdio.h>
#include<algorithm>

using namespace std;

typedef long long ll;

const int MX = 2005;
const int MOD = 1000000007;

ll D[MX][MX], T[MX][MX], E[MX][MX];
ll tot[MX];

int main()
{
    int N, M;
    scanf("%d%d", &N, &M);
    for(int j = 2; j <= M; j++) D[1][j] = 1;
    for(int i = 2; i <= N; i++){
        for(int j = 2; j <= M; j++) D[i][j] = (D[i][j-1] + D[i-1][j]) % MOD;
        for(int j = 2; j <= M; j++) D[i][j] = (D[i][j] + D[i][j-1]) % MOD;
    }
    for(int j = 2; j <= M; j++){
        for(int i = 1; i <= N; i++) D[i][j] = (D[i][j] + D[i-1][j]) % MOD;
    }
    for(int i = 1; i <= N; i++){
        for(int j = 1; j <= M; j++) E[i][j] = (E[i][j-1] + D[i][j]) % MOD;
        for(int j = 1; j <= M; j++) E[i][j] = (E[i][j-1] + E[i][j]) % MOD;
        for(int j = 1; j <= M; j++) E[i][j] = (E[i][j] - D[i][j] + MOD + 1) % MOD;
    }
    ll ans = 0;
    for(int j = 2; j <= M; j++){
        int tmp = D[N][j];
        for(int k = 1; k < N; k++){
            tmp = (tmp + D[k][j] * E[N-k][j]) % MOD;
        }
        ans = (ans + tmp * (M-j+1) ) % MOD;
    }
    printf("%lld\n", ans);
    return 0;
}

#include<stdio.h>
#include<algorithm>
#define For(i,n) for(int i=1; i<=n; i++)
#define Rep(i,n) for(int i=0; i<n; i++)
#define N 2000
#define MOD 1000000007

using namespace std;

typedef long long LL;

LL d[N+10][N+10],s1[N+10][N+10],s2[N+10][N+10];
int n,m;
int main(){
#ifndef ONLINE_JUDGE
  freopen("in.txt","r",stdin);
#endif
  scanf("%d%d",&n,&m);
  For(i,n){
    for(int j=2; j<=m; j++){
      d[i][j]=(s1[i-1][j]*j%MOD-s2[i-1][j]+1)%MOD;
      s1[i][j]=(s1[i][j-1]+d[i][j])%MOD;
      s2[i][j]=(s2[i][j-1]+d[i][j]*(j-1))%MOD;
    }
  }
  LL ans=0;
  for(int i=2; i<=m; i++){
    LL sum=0;
    For(j,n){
      sum+=i*s1[j-1][i-1]%MOD-s2[j-1][i-1]+1;
      sum%=MOD;
      ans+=sum*(i*s1[n-j][i-1]%MOD-s2[n-j][i-1]+1)%MOD*(m-i+1)%MOD;
      ans%=MOD;
    }
  }
  printf("%I64d\n",ans);
  return 0;
}

#include <stdio.h>
#include <string.h>
typedef long long LL;
const int mod = 1000000007;
LL f[2005][2005], g[2005][2005];

int main(){
    //freopen("test.in", "r", stdin);
	for(int n, m; scanf("%d%d", &n, &m)!=EOF; ){
		memset(f, 0, sizeof(f));
		memset(g, 0, sizeof(g));
		for(int i = 1; i <= n; i ++){
			LL sum = 0;
			for(int j = 2; j <= m; j ++){
				f[i][j] = (g[i-1][j]+1)%mod;
				sum = (sum + f[i][j])%mod;
				g[i][j] = (g[i][j-1] + sum)%mod;
			}
		}
		LL ans = 0;
		for(int i = 1; i <= n; i ++){
			for(int j = 2; j <= m; j ++){
				ans = ans + (f[i][j] * (g[n-i][j] - f[n-i][j] + 1)%mod) *(m - j + 1)%mod;
			}
		}
		printf("%I64d\n", ans);
	}
}

#include<cstdio>
using namespace std;
const int p=1000000007;
int n,m;
long long a[2010][2010],ans;
int main()
  {
   scanf("%d%d",&n,&m);
   for (int i=1;i<=m;i++) a[1][i]=1;
   for (int i=2;i<=n;i++)
     {
      a[i][1]=1;
      long long sum=0;
      for (int j=2;j<=m;j++)
        {
         sum=(sum+a[i-1][j])%p;
         a[i][j]=(a[i][j-1]+sum)%p;
		}
	 }
   long long ans=0;
   for (int i=1;i<=n;i++)
     for (int j=2;j<=m;j++)
       ans=ans+(a[i][j]-a[i-1][j])*a[n-i+1][j]*(m-j+1)%p;
   printf("%lld",ans);
   return 0;
  }

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int module = 1e9+7;

int n,m;
int cnt[2222][2222],cnth[2222][2222];
int sum[2222][2222];

int main()
{
//	ifstream cin("input.txt");
	//ofstream cout("output.txt");
	for (int i=2; i<=2000; i++)
	{
		cnt[1][i]=(1LL*i*(i-1)/2)%module;
		sum[1][i]=(sum[1][i-1]+cnt[1][i])%module;
	}
	for (int i=2; i<=2000; i++)
		for (int j=2; j<=2000; j++)
		{
			cnt[i][j]=(cnt[i][j-1]+sum[i-1][j])%module;
			sum[i][j]=(sum[i][j-1]+cnt[i][j])%module;
		}
	for (int i=1; i<=2000; i++)
		for (int j=0; j<=2000; j++)
			cnth[i][j]=(cnth[i-1][j]+cnt[i][j])%module;
	cin >> n >> m;
	int ans=0;
	for (int i=0; i<n; i++)
		for (int l=2; l<=m; l++)
		{
		//	int buffer = ans;
			ans = (ans + m-l+1)%module;
			int x = m-l+1;
			if (i!=n-1)
			{
				x = (1LL*x*cnth[n-i-1][l])%module;
				ans = (ans + x)%module;
			}
			if (i!=0)
			{
				ans = (ans + (1LL*(m-l+1)*(2LL*cnth[i][l-1]-cnth[i][l-2]))%module)%module;
				x = (1LL*x*(2LL*cnth[i][l-1]-cnth[i][l-2]))%module;
			}
			if (i!=0 && i!=n-1)
				ans = (ans + x)%module;
		//	cout << i << " " << l << " " << ans-buffer << endl;
		}
	cout << ans << endl;
	return 0;
}

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

struct FFT {
    struct node {
        double x,y;
        node() {}
        node(double a, double b): x(a), y(b) {}
        node operator + (const node &a) const {
            return node(this->x+a.x,this->y+a.y);
        }
        node operator - (const node a) const {
            return node(this->x-a.x,this->y-a.y);
        }
        node operator * (const node a) const {
            return node(this->x*a.x-this->y*a.y,this->x*a.y+a.x*this->y);
        }
    };

    long long M;
    vector<node> A, B, w[2];
    vector<long long> rev;
    long double pi = acos(-1.0);
    void init(long long n) {
        M = 1;
        while(M < n) M <<= 1;
        M <<= 1;
        A.resize(M); B.resize(M);
        w[0].resize(M); w[1].resize(M);
        rev.resize(M);
        for (long long i=0; i<M; i++) {
            long long j=i,y=0;
            for (long long x=1; x<M; x<<=1,j>>=1) (y<<=1)+=j&1;
            rev[i]=y;
        }
        for (long long i=0; i<M; i++) {
            w[0][i] = node( cos(2*pi*i/M),sin(2*pi*i/M) );
            w[1][i] = node( cos(2*pi*i/M),-sin(2*pi*i/M) );
        }
    }
    void ftransform( vector<node> &A, long long p ) {
        for (long long i=0; i<M; i++)
            if (i<rev[i])
                swap(A[i],A[rev[i]]);
        for (long long i=1; i<M; i<<=1)
            for (long long j=0,t=M/(i<<1); j<M; j+=i<<1)
                for (long long k=0,l=0; k<i; k++,l+=t) {
                    node x=w[p][l]*A[i+j+k];
                    node y=A[j+k];
                    A[j+k]=y+x;
                    A[j+k+i]=y-x;
                }
        if (p)
            for (long long i=0; i<M; i++)
                A[i].x/=M;
    }
    /// multiply P*Q and keeps the result in res
    ///degree of P is n and degree of Q is m
    ///P, Q is given in standard power form, in increasing
    void multiply( vector<long long> &P, vector<long long> &Q, vector<long long> &res) {
        init( max(P.size(),Q.size()) );
        for( long long i = 0; i < M; i++ )
            A[i].x = A[i].y = B[i].x = B[i].y = 0;
        for( long long i = 0; i < P.size(); i++ )
            A[i].x = P[i];
        for( long long i = 0; i < Q.size(); i++ )
            B[i].x = Q[i];
        ftransform(A,0);
        ftransform(B,0);
        for (long long k=0; k<M; k++)
            A[k] = A[k]*B[k];
        ftransform(A,1);
        res.resize(M);
        for( long long i = 0; i < M; i++ )
            res[i] = round(A[i].x);
    }
}fft;

long long dp[2005][2005];
long long pd[2005][2005];
const long long mod = 1e9 + 7;

int main() {
    long long n, m;
    cin >> n >> m;
    for(int width = 2; width <= m; width++) {
        dp[1][width] = 1;
        pd[1][width] = 1;
    }
    for(int len = 2; len <= n; len++) {
        vector <long long> mul(m,0);
        for(int i = 0; i < m; i++) {
            mul[i] = i + 1;
        }
        vector <long long> f(m + 1,0);
        for(int i = 1; i <= m; i++) f[i] = dp[len-1][i];
        vector <long long> res;
        fft.multiply(mul,f,res);
        for(int i = 2; i <= m; i++) dp[len][i] = res[i], pd[len][i] = dp[len][i] - dp[len-1][i];
    }
//    for(int i = 1; i <= n; i++) {
//        for(int j = 1; j <= m; j++) {
//            cout << i << " " << j << " " << dp[i][j] << endl;
//        }
//    }
    long long ans = 0;
    for(int base = 2; base <= m; base++) {
        vector <long long> up(n + 1, 0), down(n + 1, 0);
        for(int len = 1; len <= n; len++) {
            up[len] = pd[len][base];
            down[len] = dp[len][base];
        }
        vector <long long> res;
        fft.multiply(up,down,res);
        long long cur = 0;
        for(int len = 1; len <= n; len++) {
            long long x = (res[len + 1] * (n - len + 1))%mod;
            cur += x;
//            cout << "x: " << x << endl;
            cur %= mod;
        }
//        cout << "cur:: " << cur << endl;
        cur *= (m - base + 1);
        cur %= mod;
        ans += cur;
//        cout << "cur: " << cur << endl;
//        for(int len = 1; len <= n; len++) {
//            cout << v[len] << " ";
//        }
//        cout << endl;
//        for(int len = 1; len <= n; len++) {
//            cout << res[len] << " ";
//        }
//        cout << endl;
        ans %= mod;
    }

    cout << ans << "\n";
}

// I'm Fine ...
// I'm used to it :-(
#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;

/** +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ **/

#define ios                 ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL)
#define Time()              cerr << clock() * 1000 / CLOCKS_PER_SEC << "ms\n"
#define show(x)             cerr << #x << " = " << (x) << '\n'
#define pob                 pop_back
#define pb                  push_back
#define m_p                 make_pair
#define inf                 1061109567
#define clMAXN              const int MAXN
#define F                   first
#define S                   second

/** +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ **/

typedef long long                       ll;
typedef long double                     ld;
typedef pair<ll, ll>                    pll;
typedef long long int                   lli;
typedef pair<int, int>                  pii;
typedef unsigned long long int          ull;

/** +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ **/

//template<typename T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;
template<typename T, typename L> bool smax(T &x, L y) { return x < y ? (x = y, true) : false; }
template<typename T, typename L> bool smin(T &x, L y) { return y < x ? (x = y, true) : false; }

/** +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ **/

clMAXN = 2048;
const int mod = 1e9 + 7;
int n, m;
int c[MAXN * 3][MAXN * 3];
int dp[MAXN][MAXN];
int ans;

/** +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ **/

int main() {
    cin >> n >> m;
    for (int i = 0; i < (MAXN * 3); i++)
        for (int j = 0; j <= i; j++) {
            if (j == 0) {
                c[i][j] = 1;
                continue;
            }
            c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
        }

    for (int w = 1; w <= m; w++)
        for (int h = 0; h < n; h++)
            dp[w][h] = (c[(h << 1) + (w - 1)][w - 1] + (h ? dp[w][h - 1] : 0)) % mod;
    for (int w = 1; w <= m; w++)
        for (int h = 0; h < n; h++)
            ans = (ans + ((ll)((m - w) * c[(h << 1) + (w - 1)][w - 1]) % mod) * (ll)(dp[w][n - h - 1])) % mod;
    return cout << ans << '\n', false;
}

/*
 * temp.cpp
 *
 *  Created on: 2012-7-18
 *      Author: BSBandme
 */
#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cassert>
#include <list>
#include <iomanip>
#include <math.h>
#include <deque>
#include <utility>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <climits>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <sstream>

using namespace std;

#define mpr make_pair
typedef unsigned long long ull;
typedef long long ll;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <double, double> pdd;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef vector <double> vd;
typedef vector <string> vs;
typedef map <string, int> mpsi;
typedef map <double, int> mpdi;
typedef map <int, int> mpii;

const double pi = acos(0.0) * 2.0;
const double eps = 1e-12;
const int step[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

template <class T> inline T abs1(T a) {return a < 0 ? -a : a;}
template <class T> inline T max1(T a, T b, T c = -1234567, T d = -1234567) {
	T ans =  a > b ? a : b;
	if(c != -1234567) ans = max1(ans, c);
	if(d != -1234567) ans = max1(ans, d);
	return ans;
}
template <class T> inline T min1(T a, T b, T c = -1234567, T d = -1234567) {
	T ans = a < b ? a : b;
	if(c != -1234567) ans = min(ans, c);
	if(d != -1234567) ans = min(ans, d);
	return ans;
}
template <class T> inline T gcd1(T a, T b) {
	if(a < b) swap(a, b);
	if(a % b == 0) return b;
	return gcd1(b, a % b);
}
template <class T> inline T lb(T num) {return num & (-num); }
inline int jud(double a, double b){
	if(abs1(a - b) < eps) return 0;
	if(a < b) return -1;
	return 1;
}
template <typename it, typename t1>
inline int find(t1 val, it a, int na, bool f_small = 1, bool f_lb = 1){
	if(na == 1) return 0;
	int be = 0, en = na - 1;
	if(*a <= *(a + na - 1)){
		if(f_lb == 0) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != 1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != -1) en = mid;
			else be = mid + 1;
		}
		if(f_small && jud(*(a + be), val) == 1 && be != 0) be--;
		if(!f_small && jud(*(a + be), val) == -1 && be != na - 1) be++;
	} else {
		if(f_lb) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != -1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != 1) en = mid;
			else be = mid + 1;
		}
		if(!f_small && jud(*(a + be), val) == -1 && be != 0) be--;
		if(f_small && jud(*(a + be), val) == 1 && be != na - 1) be++;
	}
	return be;
}
inline int bitnum(ull nValue){
    nValue = ((0xaaaaaaaaaaaaaaaaull & nValue)>>1) + (0x5555555555555555ull & nValue);
    nValue = ((0xccccccccccccccccull & nValue)>>2) + (0x3333333333333333ull & nValue);
    nValue = ((0xf0f0f0f0f0f0f0f0ull & nValue)>>4) + (0x0f0f0f0f0f0f0f0full & nValue);
    nValue = ((0xff00ff00ff00ff00ull & nValue)>>8) + (0x00ff00ff00ff00ffull & nValue);
    nValue = ((0xffff0000ffff0000ull & nValue)>>16) + (0x0000ffff0000ffffull & nValue);
    nValue = ((0xffffffff00000000ull & nValue)>>32) + (0x00000000ffffffffull & nValue);
	return nValue;
}
long long pow(long long n, long long m, long long mod = 0){
	long long ans = 1;
	long long k = n;
	while(m){
		if(m & 1) {
			ans *= k;
			if(mod) ans %= mod;
		}
		k *= k;
		if(mod) k %= mod;
		m >>= 1;
	}
	return ans;
}

//.........................mi.......feng.......xian.......wai.......jin.......zhi.......challenge...............................................

const int mod = 1000000007;
const int maxn = 2110;
int dp[2][maxn][maxn];
int dp1[2][maxn][maxn];
int n, m;

inline void add(int &a, int b){
	a = a + b;
	if(a > mod) a -= mod;
}

int main(){
//	freopen("input.txt", "r", stdin);
	scanf("%d%d", &n, &m);
	for(int i = 2; i <= m; i++) {
		dp[0][1][i] = 1;
		dp[1][1][i] = (dp[0][1][i] + dp[1][1][i - 1]) % mod;
	}
	for(int i = 2; i <= n; i++){
		int sum = 0;
		for(int j = 2; j <= m; j++){
			add(sum, dp[1][i - 1][j]);
			dp[0][i][j] = sum;
			dp[1][i][j] = (dp[0][i][j] + dp[1][i][j - 1]) % mod;
		}
	}

	int ans = 0;
	for(int i = 2; i <= m; i++) {
 		int sum = 1, sum1 = 1;
		for(int j = n; j >= 1; j--){
			add(ans,  (((sum * dp[0][j][i]) % mod) * (m - i + 1)) % mod);
			add(sum1, (dp[0][n - j + 2][i] - dp[0][n - j + 1][i] + mod) % mod);
			add(sum, sum1);
		}
	}
	cout << ans << endl;

	return 0;
}

;

#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <ctime>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <cassert>
#include <bitset>

using namespace std;

const long long mod=1000000007;
long long f[2005][2005],g[2005][2005],t[2005][2005],s[2005][2005],ans;
int n,m,i,j,k;

int main() {
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	scanf("%d%d",&n,&m);
	memset(f,0,sizeof(f));
	memset(s,0,sizeof(s));
	memset(g,0,sizeof(g));
	for (i=2; i<=m; ++i) {
		f[1][i]=1;
		s[1][i]=1;
	}
	for (i=2; i<=n; ++i) {
		for (j=2; j<=m; ++j) {
			g[i][j]=(g[i][j-1]+f[i-1][j])%mod;
			f[i][j]=(f[i][j-1]+g[i][j])%mod;
			s[i][j]=(s[i-1][j]+f[i][j]-f[i-1][j])%mod;
			if (s[i][j]<0) s[i][j]+=mod;
		}
	}
	for (i=1; i<=n; ++i) {
		for (j=1; j<=m; ++j) {
			printf("%I64d ",s[i][j]);
		}
		printf("\n");
	}
	memset(f,0,sizeof(f));
	memset(t,0,sizeof(t));
	memset(g,0,sizeof(g));
	for (i=2; i<=m; ++i) {
		f[1][i]=1;
		t[1][i]=1;
	}
	for (i=2; i<=n; ++i) {
		for (j=2; j<=m; ++j) {
			g[i][j]=(g[i][j-1]+f[i-1][j])%mod;
			f[i][j]=(f[i][j-1]+g[i][j])%mod;
			t[i][j]=(t[i-1][j]+f[i][j])%mod;
		}
	}
	for (i=1; i<=n; ++i) {
		for (j=1; j<=m; ++j) {
			printf("%I64d ",t[i][j]);
		}
		printf("\n");
	}

	ans=0;
	for (i=1; i<=n; ++i) {
		for (j=2; j<=m; ++j) {
			ans+=s[i][j]*t[n-i+1][j]*(long long)(m-j+1);
			ans%=mod;
		}
	}
	printf("%I64d\n",ans);
	return 0;
}

#include <bits/stdc++.h>
typedef long long ll;
typedef double db;
#define pa pair<int,int>
#define mk make_pair
#define LOG(format, args...) fprintf(stderr, format, args)
using namespace std;
inline int rd() {
	int x=0,f=1;char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
	return x*f;
}
const int MAXN=3010;
ll N,M,ans;
ll f[MAXN][MAXN];
const ll mod=1e9+7;
/*
可以发现,只要某一层的区间长度确定了,区间开头对于答案是没有影响的,所以我们只需要记录两个状态:高度和长度
经试算可以发现,f[i][j]=f[i][j-1]+sigma(f[i-1][k](2<=k<=j))
最后枚举中间的宽度和在那一层回合
对于回合层我们还要选取瓶颈(上一层严格小于)
*/
//main========================
int main() {
	N=rd(),M=rd();
	for(int i=2;i<=M;++i) f[1][i]=1;
	for(int i=2;i<=N;++i) {
		ll sum=0;
		f[i][1]=1;//全是空白
		for(int j=2;j<=M;++j) {
			(sum+=f[i-1][j])%=mod;
			(f[i][j]=f[i][j-1]+sum)%mod;
		}
	}
	for(int i=1;i<=N;++i) for(int j=2;j<=M;++j) {
		ans=(ans+((f[i][j]-f[i-1][j])%mod+mod)*f[N-i+1][j]%mod*(M-j+1))%mod ;
	}
	printf("%lld\n",(ans%mod+mod)%mod);
	return 0;
}

#include <iostream>
#include <cstdio>

#include <queue>
#include <cstring>

using namespace std;

#define FILE_NAME "io"

const int MAXSIZE = 2001;
const long long BASE = 1000000007;

int n, m;

long long dp[MAXSIZE + 1][MAXSIZE + 1];
long long sum[MAXSIZE + 1][MAXSIZE + 1];

int main()
{
    #ifndef ONLINE_JUDGE
    freopen (FILE_NAME".in", "r", stdin);
    freopen (FILE_NAME".out", "w", stdout);
    #endif // ONLINE_JUDGE

    scanf ("%d%d", &n, &m);

    for (int l = 1; l < m; l++)
        dp[1][l] = 1;

    for (int i = 2; i <= n; i++) {
        long long sum = 0;
        for (int j = 1; j < m; j++) {
            sum += (dp[i - 1][j]) % BASE;
            dp[i][j] = (dp[i][j - 1] + sum) % BASE;
        }
    }

    for (int j = 1; j < m; j++)
        for (int t = n - 1; t >= 1; t--)
            sum[n - t][j] = (sum[n - t - 1][j] + dp[n - t][j]) % BASE;

    long long ANS = 0;
    for (int t = 1; t <= n; t++) {
        for (int j = 1; j < m; j++) {
            long long count = (sum[n - t + 1][j] * (m - j)) % BASE;
            ANS = (ANS + dp[t][j] * count) % BASE;
        }
    }

    printf ("%I64d", ANS);

    return 0;
}

#include <stdio.h>
#include <iostream>
#include <string.h>
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;

const int mod=1000000007;
int n,m;
int dp[2005][2005];
int sum1[2005][2005],sum2[2005][2005];

int main(){
    scanf("%d%d",&n,&m);
    clr(dp,0);
    for(int i=1;i<=n;i++){
        int s=0;
        for(int j=2;j<=m;j++){
            sum1[i][j]=sum2[i-1][j]+1;
            if(sum1[i][j]>=mod)sum1[i][j]-=mod;
            s+=sum1[i][j];
            if(s>=mod)s-=mod;
            sum2[i][j]=sum2[i][j-1]+s;
        }
    }
    ll ans=0;
    for(int i=1;i<=n;i++)
        for(int j=2;j<=m;j++)
            ans=(ans+(ll)sum1[i][j]*(sum2[n-i][j]-sum1[n-i][j]+1+mod)%mod*(m-j+1))%mod;
    cout<<ans<<endl;
}

#include <iostream>
#define MAXN 2005
#define MOD 1000000007

using namespace std;

int n, m;
long long res, c[MAXN][MAXN];

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

  long long p, q, s;
  for (int i = 1; i <= n; i++)
  {
    p = 1, q = 0;
    for (int j = 2; j <= m; j++)
    {
      q = (q + c[i - 1][j]) % MOD;
      p = (p + q) % MOD;
      c[i][j] = p;
    }
  }

  res = 0;
  for (int i = 1; i < n; i++)
  {
    p = 1; q = 0;
    for (int j = 2; j <= m; j++)
    {
      s = m - j + 1;
      p = (p + q) % MOD;
      q = (q + c[n - i][j]) % MOD;
      res = (res + s * (c[i][j] * p % MOD)) % MOD;
      p = (p + c[n - i][j]) % MOD;
    }

    if (i == 1 || i == n)
      for (int j = 2; j <= m; j++)
      {
        s = m - j + 1;
        res = (res + s * c[n][j]) % MOD;
      }
  }

  cout << res;

 // system("pause");
}

#include<cmath>
#include<math.h>
#include<ctype.h>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<complex>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cwchar>
#include<cwctype>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
using namespace std;
const int Mod=1e9+7;
int n,m,f[2010][2010],s,t;
long long ans;
int main()
{
	cin>>n>>m;
	for (int i=1;i<=n;i++)
	{
		s=1;
		t=0;
		for (int j=2;j<=m;j++)
		{
			t=(t+f[i-1][j])%Mod;
			s=(s+t)%Mod;
			f[i][j]=s;
		}
	}
	for (int i=1;i<=n;i++)
	{
		for (int j=2;j<=m;j++)
		{
			ans=(ans+f[n-i+1][j]*(m-j+1)%Mod*(f[i][j]-f[i-1][j]))%Mod;
		}
	}
	cout<<ans<<endl;
    return 0;
}

#include<cmath>
#include<math.h>
#include<ctype.h>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<complex>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cwchar>
#include<cwctype>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
using namespace std;
const int Mod=1e9+7;
int n,m,f[2010][2010],s,t;
long long ans;
int main()
{
	cin>>n>>m;
	for (int i=1;i<=n;i++)
	{
		s=1;
		t=0;
		for (int j=2;j<=m;j++)
		{
			t=(t+f[i-1][j])%Mod;
			s=(s+t)%Mod;
			f[i][j]=s;
		}
	}
	for (int i=1;i<=n;i++)
	{
		for (int j=2;j<=m;j++)
		{
			ans=(ans+1LL*(m-j+1)*(f[i][j]-f[i-1][j])%Mod*f[n-i+1][j])%Mod;
		}
	}
	cout<<ans<<endl;
    return 0;
}

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

struct FFT {
    struct node {
        double x,y;
        node() {}
        node(double a, double b): x(a), y(b) {}
        node operator + (const node &a) const {
            return node(this->x+a.x,this->y+a.y);
        }
        node operator - (const node a) const {
            return node(this->x-a.x,this->y-a.y);
        }
        node operator * (const node a) const {
            return node(this->x*a.x-this->y*a.y,this->x*a.y+a.x*this->y);
        }
    };

    long long M;
    vector<node> A, B, w[2];
    vector<long long> rev;
    long double pi = acos(-1.0);
    void init(long long n) {
        M = 1;
        while(M < n) M <<= 1;
        M <<= 1;
        A.resize(M); B.resize(M);
        w[0].resize(M); w[1].resize(M);
        rev.resize(M);
        for (long long i=0; i<M; i++) {
            long long j=i,y=0;
            for (long long x=1; x<M; x<<=1,j>>=1) (y<<=1)+=j&1;
            rev[i]=y;
        }
        for (long long i=0; i<M; i++) {
            w[0][i] = node( cos(2*pi*i/M),sin(2*pi*i/M) );
            w[1][i] = node( cos(2*pi*i/M),-sin(2*pi*i/M) );
        }
    }
    void ftransform( vector<node> &A, long long p ) {
        for (long long i=0; i<M; i++)
            if (i<rev[i])
                swap(A[i],A[rev[i]]);
        for (long long i=1; i<M; i<<=1)
            for (long long j=0,t=M/(i<<1); j<M; j+=i<<1)
                for (long long k=0,l=0; k<i; k++,l+=t) {
                    node x=w[p][l]*A[i+j+k];
                    node y=A[j+k];
                    A[j+k]=y+x;
                    A[j+k+i]=y-x;
                }
        if (p)
            for (long long i=0; i<M; i++)
                A[i].x/=M;
    }
    /// multiply P*Q and keeps the result in res
    ///degree of P is n and degree of Q is m
    ///P, Q is given in standard power form, in increasing
    void multiply( vector<long long> &P, vector<long long> &Q, vector<long long> &res) {
        init( max(P.size(),Q.size()) );
        for( long long i = 0; i < M; i++ )
            A[i].x = A[i].y = B[i].x = B[i].y = 0;
        for( long long i = 0; i < P.size(); i++ )
            A[i].x = P[i];
        for( long long i = 0; i < Q.size(); i++ )
            B[i].x = Q[i];
        ftransform(A,0);
        ftransform(B,0);
        for (long long k=0; k<M; k++)
            A[k] = A[k]*B[k];
        ftransform(A,1);
        res.resize(M);
        for( long long i = 0; i < M; i++ )
            res[i] = round(A[i].x);
    }
}fft;

typedef long long ll;

namespace FFT_tourist
{
    struct num
    {
        double x,y;
        num() {x=y=0;}
        num(double x,double y):x(x),y(y){}
    };
    inline num operator+(num a,num b) {return num(a.x+b.x,a.y+b.y);}
    inline num operator-(num a,num b) {return num(a.x-b.x,a.y-b.y);}
    inline num operator*(num a,num b) {return num(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
    inline num conj(num a) {return num(a.x,-a.y);}

    int base=1;
    vector<num> roots={{0,0},{1,0}};
    vector<int> rev={0,1};
    const double PI=acosl(-1.0);

    void ensure_base(int nbase)
    {
        if(nbase<=base) return;
        rev.resize(1<<nbase);
        for(int i=0;i<(1<<nbase);i++)
            rev[i]=(rev[i>>1]>>1)+((i&1)<<(nbase-1));
        roots.resize(1<<nbase);
        while(base<nbase)
        {
            double angle=2*PI/(1<<(base+1));
            for(int i=1<<(base-1);i<(1<<base);i++)
            {
                roots[i<<1]=roots[i];
                double angle_i=angle*(2*i+1-(1<<base));
                roots[(i<<1)+1]=num(cos(angle_i),sin(angle_i));
            }
            base++;
        }
    }

    void fft(vector<num> &a,int n=-1)
    {
        if(n==-1) n=a.size();
        assert((n&(n-1))==0);
        int zeros=__builtin_ctz(n);
        ensure_base(zeros);
        int shift=base-zeros;
        for(int i=0;i<n;i++)
            if(i<(rev[i]>>shift))
                swap(a[i],a[rev[i]>>shift]);
        for(int k=1;k<n;k<<=1)
        {
            for(int i=0;i<n;i+=2*k)
            {
                for(int j=0;j<k;j++)
                {
                    num z=a[i+j+k]*roots[j+k];
                    a[i+j+k]=a[i+j]-z;
                    a[i+j]=a[i+j]+z;
                }
            }
        }
    }

    vector<num> fa,fb;

    vector<int> multiply(vector<int> &a, vector<int> &b)
    {
        int need=a.size()+b.size()-1;
        int nbase=0;
        while((1<<nbase)<need) nbase++;
        ensure_base(nbase);
        int sz=1<<nbase;
        if(sz>(int)fa.size()) fa.resize(sz);
        for(int i=0;i<sz;i++)
        {
            int x=(i<(int)a.size()?a[i]:0);
            int y=(i<(int)b.size()?b[i]:0);
            fa[i]=num(x,y);
        }
        fft(fa,sz);
        num r(0,-0.25/sz);
        for(int i=0;i<=(sz>>1);i++)
        {
            int j=(sz-i)&(sz-1);
            num z=(fa[j]*fa[j]-conj(fa[i]*fa[i]))*r;
            if(i!=j) fa[j]=(fa[i]*fa[i]-conj(fa[j]*fa[j]))*r;
            fa[i]=z;
        }
        fft(fa,sz);
        vector<int> res(need);
        for(int i=0;i<need;i++) res[i]=fa[i].x+0.5;
        return res;
    }

    vector<int> multiply_mod(vector<int> &a,vector<int> &b,int m,int eq=0)
    {
        int need=a.size()+b.size()-1;
        int nbase=0;
        while((1<<nbase)<need) nbase++;
        ensure_base(nbase);
        int sz=1<<nbase;
        if(sz>(int)fa.size()) fa.resize(sz);
        for(int i=0;i<(int)a.size();i++)
        {
            int x=(a[i]%m+m)%m;
            fa[i]=num(x&((1<<15)-1),x>>15);
        }
        fill(fa.begin()+a.size(),fa.begin()+sz,num{0,0});
        fft(fa,sz);
        if(sz>(int)fb.size()) fb.resize(sz);
        if(eq) copy(fa.begin(),fa.begin()+sz,fb.begin());
        else
        {
            for(int i=0;i<(int)b.size();i++)
            {
                int x=(b[i]%m+m)%m;
                fb[i]=num(x&((1<<15)-1),x>>15);
            }
            fill(fb.begin()+b.size(),fb.begin()+sz,num{0,0});
            fft(fb,sz);
        }
        double ratio=0.25/sz;
        num r2(0,-1),r3(ratio,0),r4(0,-ratio),r5(0,1);
        for(int i=0;i<=(sz>>1);i++)
        {
            int j=(sz-i)&(sz-1);
            num a1=(fa[i]+conj(fa[j]));
            num a2=(fa[i]-conj(fa[j]))*r2;
            num b1=(fb[i]+conj(fb[j]))*r3;
            num b2=(fb[i]-conj(fb[j]))*r4;
            if(i!=j)
            {
                num c1=(fa[j]+conj(fa[i]));
                num c2=(fa[j]-conj(fa[i]))*r2;
                num d1=(fb[j]+conj(fb[i]))*r3;
                num d2=(fb[j]-conj(fb[i]))*r4;
                fa[i]=c1*d1+c2*d2*r5;
                fb[i]=c1*d2+c2*d1;
            }
            fa[j]=a1*b1+a2*b2*r5;
            fb[j]=a1*b2+a2*b1;
        }
        fft(fa,sz);fft(fb,sz);
        vector<int> res(need);
        for(int i=0;i<need;i++)
        {
            ll aa=fa[i].x+0.5;
            ll bb=fb[i].x+0.5;
            ll cc=fa[i].y+0.5;
            res[i]=(aa+((bb%m)<<15)+((cc%m)<<30))%m;
        }
        return res;
    }
    vector<int> square_mod(vector<int> &a,int m)
    {
        return multiply_mod(a,a,m,1);
    }
};

long long dp[2005][2005];
long long pd[2005][2005];
const long long mod = 1e9 + 7;

int main() {
    long long n, m;
    cin >> n >> m;
    for(int width = 2; width <= m; width++) {
        dp[1][width] = 1;
        pd[1][width] = 1;
    }
    for(int len = 2; len <= n; len++) {
        vector <long long> mul(m,0);
        for(int i = 0; i < m; i++) {
            mul[i] = i + 1;
        }
        vector <long long> f(m + 1,0);
        for(int i = 1; i <= m; i++) f[i] = dp[len-1][i];
        vector <long long> res;
        fft.multiply(mul,f,res);
        for(int i = 2; i <= m; i++) dp[len][i] = res[i], pd[len][i] = (dp[len][i] - dp[len-1][i])%mod;
    }
    long long ans = 0;
    for(int base = 2; base <= m; base++) {
        vector <int> up(n + 1, 0), down(n + 1, 0);
        for(int len = 1; len <= n; len++) {
            up[len] = pd[len][base];
            down[len] = dp[len][base];
        }
        vector <int> res;
        res = FFT_tourist::multiply_mod(up,down,mod);
        long long cur = 0;
        for(int len = 1; len <= n; len++) {
            long long x = (1ll * res[len + 1] * (n - len + 1))%mod;
            cur += x;
            cur %= mod;
        }
        cur *= (m - base + 1);
        cur %= mod;
        ans += cur;
        ans %= mod;
    }

    cout << ans << "\n";
}

//$UANAS$
#include<bits/stdc++.h>

using namespace std;

#define int long long
#define rep(i,f,l) for(int i=f;i<l;++i)
#define FOR(i,n) for(int i=0;i<n;++i)
#define sim template < class c
#define ris return * this
#define imie(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "
#define Foreach(i, x) for (__typeof(x.begin()) i = x.begin(); i != x.end(); i++)
#define pb push_back
#define SI size()
#define S second
#define F first
#define C clear()
#define pii pair<int,int>
#define B begin()
#define mp make_pair
#define E end()
#define I insert
#define piii pair<long long,pair<long long,long long> >
#define P push
#define T top()
#define PP pop()

const int MAXn=2e3+10;
const int MOD=1e7+9;
int n,m,s[MAXn],dp[MAXn][MAXn],a[MAXn],ans;

signed main(){

    cin>>n>>m;
    rep(i,1,n+1){

        dp[2][i]=i;
        s[i+1]+=i;
        a[i+1]+=i;
    }
    rep(i,3,m+1){
        rep(j,1,n+1){

            s[j]+=dp[i][j-1];
            s[j]%=MOD;
            a[j]+=s[j];
            a[j]%=MOD;
            dp[i][j]=(a[j]+1)%MOD;
        }
    }
    rep(i,1,n+1){
        rep(j,2,m+1){
            int x=
                    (dp[j][i]*(dp[j][n-i+1]-dp[j][n-i]+MOD))%MOD;
            x=(x*(m+1-j))%MOD;
            ans+=x;
            ans%=MOD;
        }
    }
    return
            cout<<ans<<endl,0;
}

#include <iomanip>
#include <algorithm>
#include <numeric>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <complex>
#include <cassert>
#include <bitset>
using namespace std;

#define forn(i,n) for(int i=0;i<(int)(n);i++)
#define si(c) ((int)(c).size())
#define forsn(i,s,n) for(int i = (int)(s); i<((int)n); i++)
#define dforsn(i,s,n) for(int i = (int)(n)-1; i>=((int)s); i--)
#define decl(v, c) typeof(c) v = c
#define forall(i, c) for(decl(i, c.begin()); i!=c.end(); ++i)
#define dforall(i, c) for(decl(i, c.rbegin()); i!=c.rend(); ++i)
#define all(c) (c).begin(), (c).end()
#define rall(c) (c).rbegin(), (c).rend()
#define D(a) cerr << #a << "=" << a << endl;
#define pb push_back
#define eb emplace_back
#define mp make_pair

#ifdef LOCAL
#define printLong(x) cout << x << endl
#define readLong(x) cin >> x
#else
#define printLong(x) printf("%I64d\n",x)
#define readLong(x) scanf("%I64d", &x)
#endif

typedef long long int tint;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<tint> vt;
typedef vector<vt> vvt;
typedef vector<double> vd;
typedef vector<vd> vvd;
typedef vector<bool> vb;
typedef vector<vb> vvb;
typedef vector<string> vs;
typedef pair<int,int> pii;
typedef vector<pii> vpii;

const int MAXN = 2020;
const int MOD = 1e9 + 7;

tint memo[MAXN][MAXN];
tint go(int w, int h) {
    if (w < 2) return 0;
    if (h == 0) return 1;

    tint &res = memo[w][h];
    if (res != -1) return res;
    res = (go(w,h-1) + 2*go(w-1,h) - go(w-2,h)) % MOD;
    if (res < 0) res += MOD;
    return res;
}

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

    int n,m; cin >> n >> m;
    fill(memo[0], memo[m+2], -1);
    forn(w,m+1) forn(h,n+1) {
        memo[w][h] = go(w,h);
    }
    forn(w,m+1) forn(h,n+1) {
        memo[w][h+1] += memo[w][h];
    }

    tint res = 0;
    forn(i,n) {
        forsn(w,2,m+1) {
            tint up = go(w,i), down = go(w,n-1-i);
            if (i < n-1) down -= go(w,n-2-i);
            res += up*down%MOD*(m+1-w)%MOD;
        }
    }
    res %= MOD; if (res < 0) res += MOD;
    cout << res << endl;

    return 0;
}

#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <ctime>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <cassert>
#include <bitset>

using namespace std;

const long long mod=1000000007;
long long f[2005][2005],g[2005][2005],t[2005][2005],s[2005][2005],ans;
int n,m,i,j,k;

int main() {
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	scanf("%d%d",&n,&m);
	memset(f,0,sizeof(f));
	memset(s,0,sizeof(s));
	memset(g,0,sizeof(g));
	for (i=2; i<=m; ++i) {
		f[1][i]=1;
		s[1][i]=1;
	}
	for (i=2; i<=n; ++i) {
		for (j=2; j<=m; ++j) {
			g[i][j]=(g[i][j-1]+f[i-1][j])%mod;
			f[i][j]=(f[i][j-1]+g[i][j])%mod;
			s[i][j]=(s[i-1][j]+f[i][j]-f[i-1][j])%mod;
			if (s[i][j]<0) s[i][j]+=mod;
		}
	}
	for (i=1; i<=n; ++i) {
		for (j=1; j<=m; ++j) {
			printf("%I64d ",s[i][j]);
		}
		printf("\n");
	}
	memset(f,0,sizeof(f));
	memset(t,0,sizeof(t));
	memset(g,0,sizeof(g));
	for (i=2; i<=m; ++i) {
		f[1][i]=1;
		t[1][i]=1;
	}
	for (i=2; i<=n; ++i) {
		for (j=2; j<=m; ++j) {
			g[i][j]=(g[i][j-1]+f[i-1][j])%mod;
			f[i][j]=(f[i][j-1]+g[i][j])%mod;
			t[i][j]=(t[i-1][j]+f[i][j])%mod;
		}
	}
	for (i=1; i<=n; ++i) {
		for (j=1; j<=m; ++j) {
			printf("%I64d ",t[i][j]);
		}
		printf("\n");
	}

	ans=0;
	for (i=1; i<=n; ++i) {
		for (j=2; j<=m; ++j) {
			ans+=s[i][j]*t[n-i+1][j]*(long long)(m-j+1);
			ans%=mod;
		}
	}
	printf("%I64d\n",ans);
	return 0;
}

#include <cstdio>

const long long mod_v = 1000000007;
const int MaxN = 2001;
long long f[MaxN][MaxN];

int main()
{
	int n, m;
	std::scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; ++i)
	{
		long long s1 = 0, s2 = 0;
		for(int j = 2; j <= m; ++j)
		{
			s1 = (s1 + f[i - 1][j]) % mod_v;
			s2 = (s2 + j * f[i - 1][j]) % mod_v;
			f[i][j] = (1 + (j + 1) * s1 - s2) % mod_v;
		}
	}

	long long ans = 0;
	for(int i = 1; i <= n; ++i)
		for(int j = 2; j <= m; ++j)
			ans = (ans + (m - j + 1) * f[i][j] * (f[n - i + 1][j] - f[n - i][j])) % mod_v;

	std::printf("%d\n", (int)ans);

	return 0;
}

#include <iostream>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <queue>
#define int long long int

using namespace std;

main()
{
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    int N, M;
    int mod = 1e9+7;
    cin>>N>>M;
    vector<vector<int> > D(N, vector<int>(M+1));
    vector<vector<int> > Sum(N, vector<int>(M+1));
    vector<vector<int> > Sum2(N, vector<int>(M+1));
    for(int len = 2; len <= M; ++ len)
    {
        D[0][len] = 1;
        Sum[0][len] = (Sum[0][len-1] + D[0][len]) % mod;
        Sum2[0][len] = (Sum2[0][len-1] + Sum[0][len]) % mod;
    }
    for(int i = 1; i < N; ++ i)
    {
        for(int len = 2; len <= M; ++ len)
        {
            D[i][len] = (1 + Sum2[i-1][len]) % mod;
            Sum[i][len] = (Sum[i][len-1] + D[i][len]) % mod;
            Sum2[i][len] = (Sum2[i][len-1] + Sum[i][len]) % mod;
            //cout<<i<<' '<<len<<' '<<D[i][len]<<endl;
        }
    }
    int ans = 0;
    int i = 0;
    for(int len = 2; len <= M; ++ len)
    {
        ans = (ans + ((M-len+1) * D[N-1-i][len]) % mod) % mod;
    }
    //cout<<ans<<endl;
    for(int i = 1; i < N; ++ i)
    {
        for(int len = 2; len <= M; ++ len)
        {
            ans = (ans + ((M-len+1) * (((D[i][len] - D[i-1][len] + mod) % mod) * D[N-1-i][len]) % mod) % mod) % mod;
        }
    }
    cout<<ans<<endl;
}

#include <bits/stdc++.h>
using namespace std;
const int MOD = 1000000007;
const int NMAX = 2015;
int dp[NMAX][NMAX], ans, n, m;
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("date.in","r",stdin);
        freopen("date.out","w",stdout);
    #endif // ONLINE_JUDGE
    cin >> n >> m;
    for(int i = 1;i <= n;++i){
        long long  s1 = 0;
        long long s2 = 0;
        for(int j = 2;j <= m; ++j)
        {
            s1 += dp[i-1][j];
            s2 += 1LL*j*dp[i-1][j]%MOD;
            s1 %= MOD;s2 %= MOD;
            dp[i][j] = (1LL+(j+1)*s1-s2+MOD)%MOD;
        }
    }
    for(int i = 1;i <= n; ++i){
        long long s1 = 0;
        long long s2 = 0;
        for(int j = 2;j <= m; ++j){
            ans += 1LL*dp[i][j]*(1+(j+1)*s1-s2+MOD)*(m-j+1)%MOD;
            s1 += dp[n-i][j];   s1 %= MOD;
            s2 += j*dp[n-i][j]; s2 %= MOD;
            ans %= MOD;
        }
    }
    cout<<ans<<"\n";
    return 0;
}

#include <iostream>
#include <cstdio>

#include <queue>
#include <cstring>

using namespace std;

#define FILE_NAME "io"

const int MAXSIZE = 2001;
const long long BASE = 1000000007;

int n, m;

long long dp[MAXSIZE + 1][MAXSIZE + 1];
long long sum[MAXSIZE + 1][MAXSIZE + 1];

long long pow (int x, int n) {
    if (n == 0) return 1;

    long long res = pow (x, n >> 1);
    res *= res;
    if (n & 1) res *= x;
    return res;
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen (FILE_NAME".in", "r", stdin);
    freopen (FILE_NAME".out", "w", stdout);
    #endif // ONLINE_JUDGE

    scanf ("%d%d", &n, &m);

    for (int l = 1; l < m; l++)
        dp[1][l] = 1;

    for (int i = 2; i <= n; i++) {
        long long sum = 0;
        for (int j = 1; j < m; j++) {
            sum += (dp[i - 1][j]) % BASE;
            dp[i][j] = (dp[i][j - 1] + sum) % BASE;
        }
    }

    for (int j = 1; j < m; j++)
        for (int t = n - 1; t >= 1; t--)
            sum[n - t][j] = (sum[n - t - 1][j] + dp[n - t][j]) % BASE;

    long long ANS = 0;
    for (int t = 1; t <= n; t++) {
        for (int j = 1; j < m; j++) {
            long long count = 0;

            count += sum[n - t][j];
            count -= dp[n - t + 1][j] * (n - t);
            count += (dp[n - t + 1][j] - dp[0][j]) * (n - t + 1);

            count %= BASE;

            ANS += (dp[t][j] * (m - j) * count) % BASE;
        }
    }

    printf ("%I64d", ANS);

    return 0;
}

#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

namespace IO {
static const int kMaxSize = 1 << 20;
char buf[kMaxSize], *S = buf, *T = buf;
bool neg;
inline bool Fetch() { return T = (S = buf) + fread(buf, 1, kMaxSize, stdin), S != T; }
inline char NC() { return S == T ? (Fetch() ? *S++ : EOF) : *S++; }
template <typename Int> inline void RI(Int &x) {
  x = neg = 0;
  char ch = NC();
  for (; isspace(ch); ch = NC())
    ;
  if (ch == '-')
    neg = true, ch = NC();
  for (; isdigit(ch); ch = NC())
    x = x * 10 + ch - '0';
  if (neg) x = -x;
}
inline char RC() {
  char ch;
  for (ch = NC(); isspace(ch); ch = NC())
    ;
  return ch;
}
inline int RS(char *s) {
  int cur = 0, ch = NC();
  for (; isspace(ch); ch = NC());
  for (; ch != EOF && !isspace(ch); ch = NC())
    s[cur++] = ch;
  return s[cur] = 0, cur;
}
} // namespace IO

using IO::RI;
using IO::RS;
using IO::RC;

const int kMaxN = 2005, kMod = 1e9 + 7;
int n, m, f[kMaxN][kMaxN];

int main() {
  RI(n), RI(m);
  for (int i = 1; i <= m; ++i) {
    f[1][i] = 1;
  }
  for (int i = 2, sum = 0; i <= n; ++i, sum = 0) {
    f[i][1] = 1;
    for (int j = 2; j <= m; ++j) {
      sum = (sum + f[i - 1][j]) % kMod;
      f[i][j] = (f[i][j - 1] + sum) % kMod;
    }
  }
  ll ans = 0;
  for (int i = 1; i <= n; ++i) {
    for (int j = 2; j <= m; ++j) {
      ans = (ans + (1LL * (m - j + 1) * (f[i][j] - f[i - 1][j])) % kMod * f[n - i + 1][j]) % kMod;
    }
  }
  printf("%lld\n", ans);
  return 0;
}

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define fi "CF179_1_4.INP"
#define fo "CF179_1_4.OUT"
#define nmax 2000+5
#define INF 1000000000
using namespace std;
typedef long long ll;
const ll mod=ll(1000000007);
//VARIABLES
int m,n;
ll f[nmax][nmax],g[nmax][nmax],S,res;
//FUNCTION PROTOTYPES

void Process();

//MAIN
int main()
{
//       freopen(fi,"r",stdin);
//       freopen(fo,"w",stdout);
       Process();
       return 0;
}

//FUNCTIONS AND PROCEDURES
void Process()
{
	scanf("%d%d",&m,&n);
	for (int j=2;j<=n;++j) f[1][j]=g[1][j]=1;
	for (int i=2;i<=m;++i)
	{
		for (int j=2;j<=n;++j)
		{
			f[i][j]=(f[i-1][j]+f[i][j-1]*2ll-f[i][j-2]+mod)%mod;
			g[i][j]=(f[i][j-1]*2ll-f[i][j-2]+mod)%mod;
		}
	}
	for (int i=1;i<=m;++i)
	for (int j=2;j<=n;++j)
	{
		f[i][j]=(f[i][j]+f[i-1][j])%mod;
		g[i][j]=(g[i][j]+g[i-1][j])%mod;
	}
//	for (int i=1;i<=m;++i)
//	for (int j=2;j<=n;++j)
//	cout << i << " " << j << "   " << f[i][j] << endl;
	for (int i=1;i<=m;++i)
	for (int j=2;j<=n;++j)
	{
		S=ll(n-j+1);
		S=(S*f[i][j]*g[m-i+1][j])%mod;
		res=(res+S)%mod;
	}
	cout << res << endl;
}

#include <bits/stdc++.h>
using namespace std;
typedef signed long long ll;

#undef _P
#define _P(...) (void)printf(__VA_ARGS__)
#define FOR(x,to) for(x=0;x<to;x++)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define ZERO(a) memset(a,0,sizeof(a))
#define MINUS(a) memset(a,0xff,sizeof(a))
//-------------------------------------------------------

int N,M;
ll mo=1000000007;

ll dp[2002][2002],dp2[2002][2002],dp3[2002][2002];

void solve() {
    int i,j,k,l,r,x,y; string s;

    cin>>N>>M;

    for(x=2;x<=2000;x++) dp[x][0]=dp2[x][0]=dp3[x][0]=1;
    for(y=1;y<=2000;y++) {
        ll tot=0;
        for(x=2;x<=2000;x++) {
            tot+=dp[x][y-1];
            dp[x][y]=(dp[x-1][y]+tot)%mo;
            dp2[x][y]=(dp[x][y]+mo-dp[x][y-1])%mo;
            dp3[x][y]=(dp3[x][y-1]+dp2[x][y])%mo;
        }
    }

    int y1,y2,w;
    ll ret=0;
    FOR(y1,N) for(y2=y1;y2<N;y2++) {
        for(w=2;w<=M;w++) ret+=dp3[w][y1]*dp3[w][N-1-y2]*(M+1-w);
    }
    cout << ret << endl;
}

int main(int argc,char** argv){
    string s;int i;
    if(argc==1) ios::sync_with_stdio(false);
    FOR(i,argc-1) s+=argv[i+1],s+='\n';
    FOR(i,s.size()) ungetc(s[s.size()-1-i],stdin);
    solve(); return 0;
}

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <math.h>

#define mp                  make_pair
#define F                   first
#define S                   second
#define pb                  push_back
#define FOR(i,j,n)          for(int i=j;i<n;i++)
#define F0R(i,j,n)          for(int i=j;i<=n;i++)
#define RFOR(i,j,n)         for(int i=n-1;i>=j;i--)
#define RF0R(i,j,n)         for(int i=n;i>=j;i--)
#define FOREACH(x,v)        for(auto x:v)
#define ITFOR(it,v)         for(__typeof(v.begin()) it =v.begin();it!=v.end();++it)
#define __in_arr__(a,j,n)   FOR(i,j,n)cin >> a[i];
#define __out_arr__(a,j,n)  FOR(i,j,n)cout << a[i];
#define LOG                 cout << "[ !" << __LINE__ << "L ] " << endl;
#define PLOG(x)             cout << "[ !" << __LINE__ << "L ] " \<<x<<endl;

using namespace std;

typedef long long ll;
typedef pair<ll,ll> pll;
typedef pair<int,int> pii;
typedef pair<int,pii> piii;
typedef vector<int> vi;
typedef vector<pii> vii;
typedef vector<ll> vl;

const int MAXN = 2e3+6.66;
const int MAXM = 100+6.66;
const ll  MOD  = 1e9+7;
ll dp[MAXN][MAXM];
ll dp1[MAXN][MAXM];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);cout.tie(NULL);
    int n,m;
    cin >> n >> m;
    F0R(i,1,n) {
        FOR(j,0,m-1) {
            if(i==1) {
                dp[i][j] = 1;
                dp1[i][j] = 1;
                continue;
            }
            FOR(k,0,j) {
                dp[i][j] = (dp[i][j] + 1LL*dp[i-1][k]*(j-k+1LL)%MOD)%MOD;
            }
            dp1[i][j] = dp[i][j]%MOD;
            dp[i][j] = (dp[i][j] + 1LL*dp[i-1][j]%MOD)%MOD;
        }
    }
    ll ans = 0LL;
    FOR(l,0,n) FOR(r,0,n-l) {
        FOR(sz,0,m-1) {
            ll WW = (dp1[l+1][sz]*1LL*dp[r+1][sz]) %MOD;
            if(WW<0) LOG;
            ans = (ans + 1LL * (n-(r+l+1)+1) * ((m-sz-1)*1LL*WW)%MOD)%MOD;
        }
    }
    cout << ans << endl;
    return 0;
}

#include<algorithm>
#include<cassert>
#include<complex>
#include<map>
#include<iomanip>
#include<sstream>
#include<queue>
#include<set>
#include<string>
#include<vector>
#include<iostream>
#include<cstring>
#define FOR(i, a, b) for(int i =(a); i <=(b); ++i)
#define FORD(i, a, b) for(int i = (a); i >= (b); --i)
#define fup FOR
#define fdo FORD
#define REP(i, n) for(int i = 0;i <(n); ++i)
#define VAR(v, i) __typeof(i) v=(i)
#define FORE(i, c) for(VAR(i, (c).begin()); i != (c).end(); ++i)
#define ALL(x) (x).begin(), (x).end()
#define SZ(x) ((int)(x).size())
#define siz SZ
#define CLR(x) memset((x), 0, sizeof(x))
#define PB push_back
#define MP make_pair
#define X first
#define Y second
#define FI X
#define SE Y
#define SQR(a) ((a)*(a))
#define DEBUG 1
#define debug(x) {if (DEBUG)cerr <<#x <<" = " <<x <<endl; }
#define debugv(x) {if (DEBUG) {cerr <<#x <<" = "; FORE(it, (x)) cerr <<*it <<", "; cout <<endl; }}
using namespace std;

typedef long long LL;
typedef long double LD;
typedef pair<int, int>P;
typedef vector<int>VI;
const int INF=1E9+7;
template<class C> void mini(C&a4, C b4){a4=min(a4, b4); }
template<class C> void maxi(C&a4, C b4){a4=max(a4, b4); }

#define maxn 2005
const LL mod = 1E9 + 7;
LL t[maxn][maxn];
LL tm[maxn][maxn];

int main(){
	ios_base::sync_with_stdio(false);
    int h, w;
    cin >> h >> w;
    fup(i, 2, w) t[1][i] = tm[1][i] = 1;
    fup(i, 2, h) {
        LL s = 0;
        fup(j, 2, w) {
            s += t[i - 1][j];
            s %= mod;
            t[i][j] = (t[i][j - 1] + s) % mod;
            tm[i][j] = (tm[i - 1][j] + t[i][j]) % mod;
        }
    }
    LL S = 0;
    fup(x, 1, h) {
        fup(szer, 2, w) {
            LL ile = tm[x][szer] * tm[h - x + 1][szer];
            if (x != 1) ile -= tm[x - 1][szer] * tm[h - x + 1][szer];
            ile %= mod;
            ile *= w - szer + 1;
            ile %= mod;
            S +=  ile;
            S %= mod;
        }
    }
    cout << S << endl;

	return 0;
}

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=2005,MD=1000000007;
int f[N][N],g[N][N];
//f[i][j]表示前i行第i行j个的方案数 g[i][j]表示前i行第i行小于等于j个的方案数
void add(int &x,int y)
{
      x+=y;
      if(x>=MD) x-=MD;
}
int main()
{
      int i,j,n,m;
      scanf("%d%d",&n,&m);
      for(i=1;i<=n;++i)
      {
         int sum=0;
         for(j=2;j<=m;++j)
         {
            add(f[i][j],g[i-1][j]+1);//上一行为空
            add(sum,f[i][j]);
            add(g[i][j],g[i][j-1]+sum);
         }
      }
      int ans=0;
      for(i=1;i<=n;++i)
      {
        for(j=2;j<=m;++j)
         ans+=(long long)f[i][j]*(g[n-i][j]-f[n-i][j]+1)%MD*(m-j+1)%MD;
        ans%MD;
        //枚举最长行
      }
      printf("%d",ans%MD);
     // system("pause");
      return 0;
}

#include <iostream>
#include <cstdio>
#include <string.h>
#include <string>
#include <algorithm>
#include <math.h>
using namespace std;

const int maxn = 2000 + 7;
const int mod = 1000000000 + 7;
int n, m, f[maxn][maxn], g[maxn][maxn];
int s[maxn][maxn];

void prework()
{
	memset(f, 0, sizeof(f));
	memset(g, 0, sizeof(g));
	for (int k = 1; k <= n; k++) {
		int sum = 0, w = 0, sumg = 0;
		for (int i = 2; i <= m; i++) {
			w = (w + f[k-1][i]) % mod;
			sum = (sum + w) % mod;
			f[k][i] = sum + 1;
			sumg = (f[k][i] + sumg) % mod;
			g[k][i] = (g[k][i-1] + sumg) % mod;
		}
	}
}

int main()
{
	while (scanf("%d%d", &n, &m)!=EOF) {
		prework();
		long long ans = 0;
		for (int i = 1; i <= n; i++) {
			for (int j = 2; j <= m; j++) {
				ans += (long long)(f[i][j])*(g[n-i][j]-f[n-i][j]+1) % mod * (m-j+1) % mod;
			}
		}
		printf("%I64d\n", ans);
	}
	return 0;
}

#include <bits/stdc++.h>
#define TASK "295D"
#define pb push_back
#define ii pair<int,int>
#define iii pair<ii,int>
#define ll long long
#define F first
#define S second
#define FOR(i, a, b) for (int i=a; i<=b; i++)
#define FOr(i, a, b) for (int i=a; i<b ; i++)
#define FOD(i, a, b) for (int i=a; i>=b; i--)
#define FOd(i, a, b) for (int i=a; i>b ; i--)
using namespace std;

const int N=(int)1e6+7;
const ll MOD=(int)1e9+7;
const ll INF=(ll)1e18+7;
ll dp[2002][2002];

ll add(ll a, ll b) {
    a+=b;
    return a>MOD ? a-MOD : a;
}

ll mul(ll a,ll b) {
    return a*b % MOD;
}
int main() {
    //freopen(TASK".INP","r",stdin);
    //freopen(TASK".OUT","w",stdout);
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n,m;
    cin >> n >> m;

    ll ans=0;

    FOR(i,2,m)
        dp[1][i]=1;
    FOR(i,1,n)
        dp[i][1]=1;
    FOR(i,2,n) {
        ll cur = 0;
        FOR(j,2,m) {
            cur=add(cur,dp[i-1][j]);
            dp[i][j]=add(dp[i][j-1],cur);
        }
    }

    FOR(i,1,n)
        FOR(j,2,m)
            ans+=mul(m-j+1,
                 mul(dp[n-i+1][j],dp[i][j]-dp[i-1][j]+MOD));

    cout << ans;
}

#include <stdio.h>
#include <iostream>
using namespace std;
const int maxn=2020;
const int mod=1e9+7;
typedef long long ll;
//======================================
int f[maxn][maxn],g[maxn][maxn];

int main()
{
    int n,m,i,j;
    cin>>n>>m;
    for(i=1;i<=n;i++){
        ll sum=0;
        for(j=2;j<=m;j++){
            f[i][j]=(f[i][j]%mod+g[i-1][j]%mod+1)%mod;
            sum=(sum%mod+f[i][j])%mod;
            g[i][j]=(g[i][j-1]%mod+sum)%mod;
        }
    }
    ll ans=0;
    for(i=1;i<=n;i++){
        for(j=2;j<=m;j++){
            ans=1ll*(ans%mod+f[i][j]*(g[n-i][j]-f[n-i][j]+1)%mod*(m-j+1)%mod)%mod;
        }
    }
    cout<<ans<<endl;
    return 0;
}

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <math.h>

#define mp                  make_pair
#define F                   first
#define S                   second
#define pb                  push_back
#define FOR(i,j,n)          for(int i=j;i<n;i++)
#define F0R(i,j,n)          for(int i=j;i<=n;i++)
#define RFOR(i,j,n)         for(int i=n-1;i>=j;i--)
#define RF0R(i,j,n)         for(int i=n;i>=j;i--)
#define FOREACH(x,v)        for(auto x:v)
#define ITFOR(it,v)         for(__typeof(v.begin()) it =v.begin();it!=v.end();++it)
#define __in_arr__(a,j,n)   FOR(i,j,n)cin >> a[i];
#define __out_arr__(a,j,n)  FOR(i,j,n)cout << a[i];
#define LOG                 cout << "[ !" << __LINE__ << "L ] " << endl;
#define PLOG(x)             cout << "[ !" << __LINE__ << "L ] " \<<x<<endl;

using namespace std;

typedef long long ll;
typedef pair<ll,ll> pll;
typedef pair<int,int> pii;
typedef pair<int,pii> piii;
typedef vector<int> vi;
typedef vector<pii> vii;
typedef vector<ll> vl;

const int MAXN = 2e3+6.66;
const int MAXM = 10+6.66;
const ll  MOD  = 1e9+7;
ll dp[MAXN][MAXM];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);cout.tie(NULL);
    int n,m;
    cin >> n >> m;
    FOR(i,0,m)
        dp[0][i] = 1LL;
    F0R(i,1,n) {
        FOR(j,0,m-1) {
            F0R(k,0,j) {
                dp[i][j] = (dp[i][j] + dp[i-1][k]*(j-k+1));
            }
        }
    }
    ll ans = 0LL;
    FOR(l,0,n) FOR(r,0,n-l) {
        FOR(sz,0,m-1) {
            ans = (ans+1LL*(m-sz-2+1)*dp[l][sz]*dp[r][sz]%MOD)%MOD;
        }
    }
    cout << ans << endl;
    return 0;
}

#include <stdio.h>
#include <string.h>
typedef long long LL;
const int mod = 1000000007;
LL f[2005][2005], g[2005][2005];

int main(){
    //freopen("test.in", "r", stdin);
	for(int n, m; scanf("%d%d", &n, &m)!=EOF; ){
		memset(f, 0, sizeof(f));
		memset(g, 0, sizeof(g));
		for(int i = 1; i <= n; i ++){
			LL sum = 0;
			for(int j = 2; j <= m; j ++){
				f[i][j] = (g[i-1][j]+1)%mod;
				sum = (sum + f[i][j])%mod;
				g[i][j] = (g[i][j-1] + sum)%mod;
			}
		}
		LL ans = 0;
		for(int i = 1; i <= n; i ++){
			for(int j = 2; j <= m; j ++){
				ans = ans + (f[i][j] * (g[n-i][j] - f[n-i][j] + 1)%mod) *(m - j + 1)%mod;
			}
		}
		printf("%I64d\n", ans);
	}
}

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int f[2001][2001];
int g[2001][2001];
int n, m;
int mod = (int) 1e9+7;
void add(int& x, int y)
{
	x += y;
	if(x > mod)
		x -= mod;
	return ;
}
int main()
{
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++)
	{
		int x = 0;
		for(int j = 2; j <= m; j++)
		{
			add(f[i][j], g[i-1][j] + 1);
			add(x, f[i][j]);
			add(g[i][j], g[i][j-1] + x);
		}
	}
	long long ans = 0;
	for(int i = 1; i <= n; i++)
	{
		for(int j = 2; j <= m; j++)
			ans += (long long)((f[i][j] * (g[n-i][j] - f[n-i][j] + 1))%mod)*(m-j+1)%mod;
		ans %= mod;
	}
	int ia;
	ia = ans % mod;
	printf("%d\n", ia);
	return 0;
}

// God & me
// Don't forget me ...
#include <bits/stdc++.h>
#define X first
#define Y second
using namespace std;
template <class T, class L> bool smax(T &x, L y){  return x < y ? ( x = y, 1) : 0;  }
template <class T, class L> bool smin(T &x, L y){  return y < x ? ( x = y, 1) : 0;  }
typedef pair <int, int> pii;
typedef long long ll;

const int maxn = 2e3 + 17, mod = 1e9 + 7;
int n, m, mon[maxn][maxn], ps[maxn], ans;
int main(){
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n >> m;
    fill(mon[1], mon[2], 1);
    for(int h = 2; h < maxn; h++){
	partial_sum(mon[h - 1], mon[h], ps, [](const int &x, const int &y){  return (x + y) % mod;  });
	for(int w = 0; w < maxn; w++)
	    mon[h][w] = (ps[w] + (w ? mon[h][w - 1] : 0)) % mod;
    }
    for(int h = 2; h < maxn; h++)
	for(int w = 0; w < maxn; w++)
	    (mon[h][w] += mon[h - 1][w]) %= mod;
    for(int row = 0; row < n; row++)
	for(int len = 0; len <= m - 2; len++)
	    (ans += (ll) (mon[row + 1][len] - mon[row][len]) * mon[n - row][len] % mod * (m - 1 - len) % mod) %= mod;
    cout << ans << '\n';
    return 0;
}

#include <iostream>
#define L first
#define R second
#define MP make_pair
#define LLI long long int
using namespace std;

const LLI MX = 2100 , MOD = 100000*10000+7;
LLI dp[MX][MX], ans , sum[MX][MX] ,m ,n;

int main(){
	//ios_base::sync_with_stdio(false);
	cin >> n >> m;
	for(LLI i=2;i<=m;i++){
		dp[1][i] = i * (i - 1) / 2;
		sum[1][i] = dp[1][i];
	}
	for(LLI i=2;i<=n;i++)
		for(LLI j=2;j<=m;j++){
			dp[i][j] = dp[i-1][j] + dp[i][j-1] + dp[i][j-1] - dp[i][j-2];
			if(dp[i][j] > MOD) dp[i][j] -= MOD;
			sum[i][j] = sum[i-1][j] + dp[i][j];
			if(sum[i][j] > MOD ) sum[i][j] -= MOD;
		}
	for(LLI i=1;i<=n;i++){
		for(LLI j=2;j<=m;j++){
			ans += (m-j+1) * (((1 + sum[i-1][j] + MOD) % MOD) * (1 + sum[n-i][j-1] + sum[n-i][j-1] - sum[n-i][j-2]+MOD) % MOD);
			if( ans > MOD)
				ans -= MOD;
		}
	}
	if( ans > MOD)
		ans -= MOD;
	cout << ans << endl;
}

#include <iostream>

using namespace std;

typedef long long ll;

ll half[2020][2020]; // dp[length_of_bottom][max_height]
ll half_partial[2020][2020]; // any height [1..h]
ll cavetop[2020][2020];
const ll mod = 1000000007;
ll total = 0;

#define MOD(x) ((x + 1000000007) % 1000000007)

int N,M;

int main()
{
    ll partial, skewed;
    cin >> N >> M;
    for(int h=1;h<=N;h++) half[1][h] = 0;
    for(int i=2;i<=M;i++) half[i][1] = 1;
    for(int h=2;h<=N;h++)
    {
        partial = 0;
        skewed = 0;
        for(int l=2;l<=M;l++)
        {
            partial = MOD(partial + half[l][h-1]);
            skewed = MOD(skewed + partial);
            half[l][h] = skewed; // allows repeated lengths
            cavetop[l][h] = MOD(skewed - half[l][h-1]); // no repeated length h
            //cout << "h=" << h << " l=" << l << ' ' << cavetop[l][h] << endl;
        }
    }
    for(int l=2;l<=M;l++) cavetop[l][1] = 1;
    for(int h=1;h<=N;h++) // accumulate
        for(int l=2;l<=M;l++)
            cavetop[l][h] = MOD(cavetop[l][h] + cavetop[l][h-1]);
    //cout << cavetop[4][1] << ' ' << cavetop[4][2] << ' ' << cavetop[4][3] << ' ' << cavetop[4][4] << endl;
    ll acc, top, bot;
    for(int l=2;l<=M;l++)
    {
        acc = 0;
        top = 0;
        for(int h=1;h<=N;h++) top = MOD(top + cavetop[l][h]);
        bot = cavetop[l][1];
        for(int h=1;h<=N;h++)
        {
            cout << top << " " << bot << endl;
            acc = MOD(acc + top*bot);
            top = MOD(top - cavetop[l][N+1-h]);
            bot = MOD(cavetop[l][h+1]);
        }
        //cout << "l=" << l << " acc=" << acc << endl;
        total = MOD(total + acc*(M-l+1));
        //cout << "l=" << l << " " << total << endl;
    }
    cout << total;
    return 0;
}

#include<bits/stdc++.h>
#define MP make_pair
#define R second
#define L first
using namespace std;
typedef long long lint;
const lint mod=1000000007;
const int maxn=2000+100;
lint dp[maxn][maxn];
lint sum[maxn][maxn];
int main(){
	int n, m;
	cin >> n >> m;
	for(int j=1;j<=m;j++)
		dp[1][j]=j*(j-1)/2;
	for(int i=2;i<=n;i++)
		for(int j=1;j<=m;j++)
			dp[i][j]=(dp[i-1][j]+dp[i][j-1]*2-dp[i][j-2])%mod;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			sum[i][j]=(sum[i-1][j]+dp[i][j])%mod;
	lint ans=0;
	for(int t=1;t<=n;t++)
		for(int j=2;j<=m;j++)
			ans+=((m-j+1)%mod*((sum[t-1][j]+1)*(1+sum[n-t][j-1]*2-sum[n-t][j-2])%mod)%mod)%mod;

	cout << ans << endl;
}

#include<stdio.h>
#include<algorithm>
#define For(i,n) for(int i=1; i<=n; i++)
#define Rep(i,n) for(int i=0; i<n; i++)
#define N 2000
#define MOD 1000000007

using namespace std;

typedef long long LL;

LL d[N+10][N+10],s1[N+10][N+10],s2[N+10][N+10];
int n,m;
int main(){
#ifndef ONLINE_JUDGE
  freopen("in.txt","r",stdin);
#endif
  scanf("%d%d",&n,&m);
  For(i,n){
    for(int j=2; j<=m; j++){
      d[i][j]=(s1[i-1][j]*j%MOD-s2[i-1][j]+1)%MOD;
      s1[i][j]=(s1[i][j-1]+d[i][j])%MOD;
      s2[i][j]=(s2[i][j-1]+d[i][j]*(j-1))%MOD;
    }
  }
  LL ans=0;
  for(int i=2; i<=m; i++){
    LL sum=0;
    For(j,n){
      sum+=i*s1[j-1][i-1]%MOD-s2[j-1][i-1]+1;
      sum%=MOD;
      ans+=sum*(i*s1[n-j][i-1]%MOD-s2[n-j][i-1]+1)%MOD*(m-i+1)%MOD;
      ans%=MOD;
    }
  }
  printf("%I64d\n",ans);
  return 0;
}

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
using namespace std;
namespace zyt
{
	template<typename T>
	inline void read(T &x)
	{
		char c;
		bool f = false;
		x = 0;
		do
			c = getchar();
		while (c != '-' && !isdigit(c));
		if (c == '-')
			f = true;
		do
			x = x * 10 + c - '0', c = getchar();
		while (isdigit(c));
		if (f)
			x = -x;
	}
	template<typename T>
	inline void write(T x)
	{
		static char buf[20];
		char *pos = buf;
		if (x < 0)
			putchar('-'), x = -x;
		do
			*pos++ = x % 10 + '0';
		while (x /= 10);
		while (pos > buf)
			putchar(*--pos);
	}
	typedef long long ll;
	const int N = 2e3 + 10, Jumpmelon = 1000000007;
	int n, m, f[N][N];//f[i][j]: The number of methods to paint a half-graph with exactly i rows and j columns
	//f[i][j] = sigma(k * f[i - 1][j - k + 1])
	//f[i][j] - f[i][j - 1] = sigma(f[i - 1][k])(k from 1 to j)
	int g[N][N];//a whole graph
	int sum[N][N];
	int work()
	{
		read(n), read(m);
		if (m < 2)
		{
			write(0);
			return 0;
		}
		for (int i = 2; i <= m; i++)
			f[1][i] = 1, sum[1][i] = sum[1][i - 1] + 1;
		for (int i = 2; i <= n; i++)
			for (int j = 2; j <= m; j++)
			{
				f[i][j] = (f[i][j - 1] + sum[i - 1][j]) % Jumpmelon;
				sum[i][j] = (sum[i][j - 1] + f[i][j]) % Jumpmelon;
			}
		int ans = 0;
		for (int i = 1; i <= n; i++)
			for (int j = 2; j <= m; j++)
			{
				g[i][j] = f[i][j];//only the upper part
				for (int k = 1; k < i; k++)
				{
					int sum = 0;
					for (int x = 2; x < j; x++)
						sum = (sum + (ll)f[i - k][x] % Jumpmelon * (j - x + 1) % Jumpmelon) % Jumpmelon;
					g[i][j] = (g[i][j] + f[k][j] * sum % Jumpmelon) % Jumpmelon;
				}
				ans = (ans + (ll)g[i][j] * (n - i + 1) % Jumpmelon * (m - j + 1) % Jumpmelon) % Jumpmelon;
			}
		write(ans);
		return 0;
	}
}
int main()
{
	return zyt::work();
}

#include <iostream>
#define L first
#define R second
#define MP make_pair
#define LLI long long int
using namespace std;

const LLI MX = 2100 , MOD = 100000*10000+7;
LLI dp[MX][MX], ans , sum[MX][MX] ,m ,n;

int main(){
	//ios_base::sync_with_stdio(false);
	cin >> n >> m;
	for(LLI i=2;i<=m;i++){
		dp[1][i] = i * (i - 1) / 2;
		sum[1][i] = dp[1][i];
	}
	for(LLI i=2;i<=n;i++)
		for(LLI j=2;j<=m;j++){
			dp[i][j] = dp[i-1][j] + dp[i][j-1] + dp[i][j-1] - dp[i][j-2];
			if(dp[i][j] > MOD) dp[i][j] -= MOD;
			sum[i][j] = sum[i-1][j] + dp[i][j];
			sum[i][j] %= MOD;
			sum[i][j] = (sum[i][j]+MOD)%MOD;
		}
	for(LLI i=1;i<=n;i++){
		for(LLI j=2;j<=m;j++){
			ans += (m-j+1) * (((1 + sum[i-1][j] + MOD) % MOD) * (1 + sum[n-i][j-1] + sum[n-i][j-1] - sum[n-i][j-2]+MOD) % MOD);
			ans %= MOD;
			ans = (ans + MOD) % MOD;
		}
	}
	ans %= MOD;
	ans = (ans+MOD) % MOD;
	cout << ans << endl;
}

#include <bits/stdc++.h>
typedef long long LL;
#define rep(i,n) for(int i = 0;i < n;i ++)

const int N = 2014;
const int mod = 1e9 + 7;
int dp[N][N], f[N][N];
void add(int &x, int val) {
	x += val;
	if(x >= mod)
		x -= mod;
}
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	int ans = 0;
	for(int i = 0; i <= n; i ++)	f[i][1] = 1;
	for(int j = 0; j <= m; j ++)	f[0][j] = 1;
	for(int i = 1; i <= n; i ++) {
		int sum = 0;
		for(int j = 2; j <= m; j ++) {
			add(dp[i][j], f[i - 1][j]);
			add(sum, dp[i][j]);
			add(f[i][j], sum);
			add(f[i][j], f[i][j - 1]);
		}
	}
	for(int i = 1; i <= n; i ++) {
		for(int j = 2; j <= m; j ++) {
			int t = (f[n - i][j] - dp[n - i][j] + mod) % mod;
			t = (LL)t * dp[i][j] * (m - j + 1) % mod;
			add(ans, t);
		}
	}
	printf("%d\n", ans);
	return 0;
}

#include <bits/stdc++.h>
typedef long long ll;
typedef double db;
#define pa pair<int,int>
#define mk make_pair
#define LOG(format, args...) fprintf(stderr, format, args)
using namespace std;
inline int rd() {
	int x=0,f=1;char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
	return x*f;
}
const int MAXN=3010;
ll N,M,ans;
ll f[MAXN][MAXN];
const int mod=1e9+7;
/*
可以发现,只要某一层的区间长度确定了,区间开头对于答案是没有影响的,所以我们只需要记录两个状态:高度和长度
经试算可以发现,f[i][j]=f[i][j-1]+sigma(f[i-1][k](2<=k<=j))
最后枚举中间的宽度和在那一层回合
对于回合层我们还要选取瓶颈(上一层严格小于)
*/
//main========================
int main() {
	N=rd(),M=rd();
	for(int i=2;i<=M;++i) f[1][i]=1;
	for(int i=2;i<=N;++i) {
		int sum=0;
		f[i][1]=1;//全是空白
		for(int j=2;j<=M;++j) {
			(sum+=f[i-1][j])%=mod;
			(f[i][j]=f[i][j-1]+sum)%mod;
		}
	}
	for(int i=1;i<=N;++i) for(int j=2;j<=M;++j) {
		ans=(ans+(f[i][j]-f[i-1][j]+mod)*f[N-i+1][j]%mod*(M-j+1))%mod ;
	}
	printf("%lld\n",ans);
	return 0;
}

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <math.h>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <string>
#define clr(x,y) memset(x,y,sizeof(x))
#define forn(i,n) for(int i=0;i<n;i++)
#define ll long long
using namespace std;

ll mod = 1000000007;
int i,j,n,m;
ll dp[2005][2005],a[2005][2005],b[2005][2005];

int main(){
//    freopen("d:\\in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++){
        for(j=2;j<=m;j++){
            dp[i][j]=1+a[i-1][j]*j-b[i-1][j];
            if(dp[i][j]>=mod) dp[i][j]%=mod;
        }
        for(j=2;j<=m;j++){
            a[i][j]+=a[i][j-1]+dp[i][j];
            if(a[i][j]>=mod) a[i][j]%=mod;
        }
        for(j=2;j<=m;j++){
            b[i][j]+=b[i][j-1]+dp[i][j]*(j-1);
            if(b[i][j]>=mod) b[i][j]%=mod;
        }
    }
//    printf("%d %d %d\n",dp[2][2],a[1][2],b[1][2]);
    ll ans=0;
    for(i=1;i<=n;i++){
        for(j=2;j<=m;j++){
            ll temp=dp[i][j];
            temp*=(1+a[n-i][j]*j-b[n-i][j]-dp[n-i][j]);
            if(temp>=mod||temp<=-mod) temp%=mod;
            ans+=temp*(m-j+1);
            if(ans<=-mod||ans>=mod) ans%=mod;
        }
    }
    ans=(ans%mod+mod)%mod;
    printf("%I64d\n",ans);
    return 0;
}

#include<cmath>
#include<math.h>
#include<ctype.h>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<complex>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cwchar>
#include<cwctype>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
using namespace std;
const int Mod=1e9+7;
int n,m,f[2010][2010],s,t;
long long ans;
int main()
{
	cin>>n>>m;
	for (int i=1;i<=n;i++)
	{
		s=1;
		t=0;
		for (int j=2;j<=m;j++)
		{
			t=(t+f[i-1][j])%Mod;
			s=(s+t)%Mod;
			f[i][j]=s;
		}
	}
	for (int i=1;i<=n;i++)
	{
		for (int j=2;j<=m;j++)
		{
			ans=(ans+(n-i+1)*(m-j+1)*(f[i][j]-f[i-1][j]))%Mod;
		}
	}
	cout<<ans<<endl;
    return 0;
}

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <math.h>

#define mp                  make_pair
#define F                   first
#define S                   second
#define pb                  push_back
#define FOR(i,j,n)          for(int i=j;i<n;i++)
#define F0R(i,j,n)          for(int i=j;i<=n;i++)
#define RFOR(i,j,n)         for(int i=n-1;i>=j;i--)
#define RF0R(i,j,n)         for(int i=n;i>=j;i--)
#define FOREACH(x,v)        for(auto x:v)
#define ITFOR(it,v)         for(__typeof(v.begin()) it =v.begin();it!=v.end();++it)
#define __in_arr__(a,j,n)   FOR(i,j,n)cin >> a[i];
#define __out_arr__(a,j,n)  FOR(i,j,n)cout << a[i];
#define LOG                 cout << "[ !" << __LINE__ << "L ] " << endl;
#define PLOG(x)             cout << "[ !" << __LINE__ << "L ] " \<<x<<endl;

using namespace std;

typedef long long ll;
typedef pair<ll,ll> pll;
typedef pair<int,int> pii;
typedef pair<int,pii> piii;
typedef vector<int> vi;
typedef vector<pii> vii;
typedef vector<ll> vl;

const int MAXN = 2e3+6.66;
const int MAXM = 2e3+6.66;
const ll  MOD  = 1e9+7;
ll dp[MAXN][MAXM];
ll dp1[MAXN][MAXM];
ll par[MAXN][MAXM];
ll par2[MAXN][MAXM];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);cout.tie(NULL);
    int n,m;
    cin >> n >> m;
    FOR(sz,0,m-1)
        dp[0][sz] = 1;
    F0R(i,1,n) {
        FOR(j,0,m-1) {
            if(i==1) {
                dp[i][j] = 1;
                dp1[i][j] = 1;
                par[i][j] = j+1;
                par2[i][j] = par2[i][j-1] + j+1;
                continue;
            }
            dp1[i][j] = (1+(2+j)*par[i-1][j-1]-par2[i-1][j-1])%MOD;
            dp[i][j] = (1+(2+j)*par[i-1][j]-par2[i-1][j])%MOD;
            par[i][j] = (par[i][j-1] + dp[i][j])%MOD;
            par2[i][j] = (par2[i][j-1] + (1LL * (j+1LL)*dp[i][j])%MOD)%MOD;
        }
    }
    ll ans = 0LL;
    FOR(t,0,n) FOR(sz,0,m-1) {
        ans = (ans + (((m-sz-1LL) * 1LL * dp[t+1][sz])%MOD * dp1[n-t][sz])%MOD)%MOD;
    }
    cout << ans << endl;
    return 0;
}

#include <cstdio>
const int N = 2009,MOD = 1000000007;
int n,m,ans,f[N][N];
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("295D.in","r",stdin);
	freopen("295D.out","w",stdout);
	#endif
	scanf("%d%d",&n,&m);
	if (m == 1) return puts("0"),0;
	for (int i = 1; i <= n; ++i) {
		int x = 1,y = 0;
		for (int j = 1; j < m; ++j) {
			y = (y + f[i - 1][j]);
			x = (x + y) % MOD;
			f[i][j] = x;
		}
	}
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j < m; ++j)
			ans = (ans + 1ll * f[i][j] * (m - j) % MOD * (f[n - i + 1][j] - f[n - i][j]) % MOD);
	if (ans < 0) ans += MOD;
	printf("%d\n",ans);
}

#include <iostream>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
#include <string>
#include <string.h>
#include <sstream>
#include <queue>
#include <map>
#include <set>
#include <cstring>
#include <cmath>
#include <unordered_map>
#include <cassert>
#include <bitset>
#include <string.h>

using namespace std;

#define mod (1000000007)
const int MaxN = 2100;

inline long long add (long long a, long long b) {
  long long c = a + b;
  if (c >= mod) {
    c -= mod;
  }
  return c;
}

inline long long mul (long long a, long long b) {
  return (a * b) % mod;
}

int n, m;
long long D[MaxN][MaxN], D2[MaxN][MaxN];

int main() {
  scanf("%d %d", &n, &m);
  if (n > 1000) {
  	cout << 0 << endl;
  	return 0;
  }
  for (int i = 2; i <= m; i++) {
    D[0][i] = 1;
    D2[0][i] = 1;
  }
  for (int i = 1; i < n; i++) {
    long long sum = 0;
    for (int j = 2; j <= m; j++) {
      sum = add(sum, D[i - 1][j]), D[i][j] = add(D[i][j - 1],sum);
    }
    for (int j = 2; j <= m; j++) {
      D[i][j] = add(D[i][j], 1), D2[i][j] = add(D[i][j], mod - D[i - 1][j]);
    }
  }
  long long ans = 0;
  for (int i = 0; i < n; i++) {
    for (int j = 2; j <= m; j++) {
      ans = add(ans, mul(m - j + 1, mul(D[i][j], D2[n - i - 1][j])));
    }
  }
  printf("%I64d\n", ans);
  return 0;
}

#include<cmath>
#include<math.h>
#include<ctype.h>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<complex>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cwchar>
#include<cwctype>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
using namespace std;
const int Mod=1e9+7;
int n,m,f[2010][2010],s,t;
long long ans;
int main()
{
	cin>>n>>m;
	for (int i=1;i<=n;i++)
	{
		s=1;
		t=0;
		for (int j=2;j<=m;j++)
		{
			t=(t+f[i-1][j])%Mod;
			s=(s+t)%Mod;
			f[i][j]=s;
		}
	}
	for (int i=1;i<=n;i++)
	{
		for (int j=2;j<=m;j++)
		{
			ans=(ans+f[n-i+1][j]*(m-j+1)*(f[i][j]-f[i-1][j]))%Mod;
		}
	}
	cout<<ans<<endl;
    return 0;
}

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define rep(i,l,r) for(int i = l;i <= r;++ i)
#define Add(a,b) (a + b >= Mod ? a + b - Mod : a + b)
using namespace std;
typedef long long ll;
const int Mod = 1000000007;
int n,m;
ll f[3003][3003],sum,ssum,ans = 0;
int main()
{
    scanf("%d%d",&n,&m);
	rep(i,2,m) f[1][i] = 1;
	rep(i,2,n){
	   sum = ssum = 0;
	   rep(j,1,m){
	      sum = Add(sum,f[i - 1][j]);
		  ssum = Add(ssum,sum);
		  f[i][j] = Add(f[i][j],ssum);// f[i][j] = f[i - 1][1] * j + ... f[i - 1][j] * 1;
	   }
	}
	rep(i,2,n)
	 rep(j,1,m)
	    f[i][j] = Add(f[i][j],f[i - 1][j]);
	rep(i,1,n)
	 rep(j,1,m)
	   ans = Add(ans,f[i][j] * f[n - i + 1][j] % Mod * (m - j + 1) % Mod);
	rep(i,1,n - 1)
	 rep(j,1,m)
	   ans = (ans - f[i][j] * f[n - i][j] % Mod * (m - j + 1) % Mod) % Mod;
	cout<<ans<<endl;
	return 0;
}

#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<map>
#include<vector>
#include<cmath>
#define pb push_back
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define per(i,j,k) for(int i=j;i>=k;i--)
#define fi first
#define se second
#define pii pair<int,int>
using namespace std;
typedef long long LL;
typedef double db;
#define jsb 1000000007
int n,m;
int f[2005][2005],g[2005][2005];
inline void ADD(int &x,int y){
	x+=y;if(x>=jsb)x-=jsb;
}
int main(){
	scanf("%d%d",&n,&m);
	rep(i,1,n)
	{
		int sum=0;
		rep(j,2,m){
			ADD(f[i][j],g[i-1][j]+1);
			ADD(sum,f[i][j]);
			ADD(g[i][j],(sum+g[i][j-1])%jsb);
		}
	}
	int ans=0;
	rep(i,1,n)rep(j,1,m)ADD(ans,f[i][j]*1ll*(g[n-i][j]-f[n-i][j]+1)%jsb*1ll*(m-j+1)%jsb);
	printf("%d\n",ans);
	return 0;
}

//Michał Glapa
#include<cstdio>
#include<set>
#include<vector>
#include<algorithm>
#include<queue>
#include<map>
#include<cstdlib>
#include<time.h>
#include<stack>
#include<cmath>
#include<iostream>
#include<cstring>
#include<tr1/unordered_set>
#include<tr1/unordered_map>
using namespace std;
#define FOR(i,j,k) for(int i=j;i<k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define ll long long
#define pii  pair<int, int>
#define vi vector<int >
#define pb push_back
#define mp make_pair
#define make(n) int n; scanf("%d",&n)
#define st first
#define nd second
#define INF 2000000001
#define VAR(i,n) __typeof(n) i = (n)
#define FOREACH(i,c) for(VAR(i,(c).begin());i!=(c).end();i++)
#define FORDEACH(i,c) for( VAR(i,(c).rbegin(),i!=(c).rend();i++)
#define REP(i,n) FOR(i,0,n)
#define ld long double
const long long INFLL = (ll)INF * (ll)INF;
const ld EPS = 10e-9;

#define MAXN 2007
#define int long long

int dp[MAXN][MAXN];
int dp2[MAXN][MAXN];
int MOD = (10e9)+7;
main()

{
    int n,m;
    scanf("%I64d %I64d",&n,&m);
    //DP
    for(int i=0;i<=m-2;i++)
        dp[i][0]=1;
    for(int h=1;h<n;h++)
    {
        int sum=0;
        int val=0;
        for(int l=0;l<=m-2;l++)
        {
            sum+=dp[l][h-1];
            val+=sum;
            sum%=MOD;
            val%=MOD;
            dp[l][h]=val;

        }
    }
    //DP2
    for(int l=0;l<=m-2;l++)
        dp2[l][0]=dp[l][0];
    for(int h=1;h<n;h++)
    {
        for(int l=0;l<=m-2;l++)
            dp2[l][h] =( dp2[l][h-1]+dp[l][h])%MOD;
    }
    //res
    int res=0;
    for(int i=0;i<n;i++)
    {
        for(int l=0;l<=m-2;l++)
        {
            int tmp=(dp2[l][i]*(dp2[l][n-1-i] - (n-1-i >0 ? dp2[l][n-2-i] : 0)));
            tmp%=MOD;
            tmp*=m-l-1;
            tmp%=MOD;
            //printf("%d\n",tmp);
            res+=tmp;
            res%=MOD;
        }
    }
    printf("%I64d\n",res);

}

#include <bits/stdc++.h>

#define long long long

using namespace std;

const int N = 1e2 + 10;
const int BASE = 1e9 + 7;

int n, m;
int dp[N][N];

void Add(int &a, int b) {
    a = (a + b) % BASE;
    if (a >= BASE) a -= BASE;
    if (a < 0) a += BASE;
}

int Mul(int a, int b) {
    return 1LL * a * b % BASE;
}

int main() {
    ios_base::sync_with_stdio(false); cin.tie(NULL);
    cin >> n >> m;
    if (m <= 1) {
        cout << 0;
        return 0;
    }
    for (int i = 1; i <= n; ++i) {
        int p = 0, q = 0;
        for (int j = 2; j <= m; ++j) {
            Add(p, dp[i - 1][j]);
            Add(q, Mul(dp[i - 1][j], j));
            dp[i][j] = 1 + Mul(p, j + 1) - q;
            Add(dp[i][j], 0);
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; ++i)
        for (int j = 2; j <= m; ++j) {
            int w = Mul(dp[i][j], dp[n - i + 1][j]);
                w = Mul(w, m - j + 1);
            Add(ans, w);
            if (i < n) {
                w = Mul(dp[i][j], dp[n - i][j]);
                w = Mul(w, m - j + 1);
                Add(ans, -w);
            }
        }
    cout << ans << '\n';
    return 0;
}