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.

Input

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

Output

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

Examples

Input

1 1


Output

0


Input

4 4


Output

485


Input

3 5


Output

451
import java.util.*;
import java.io.*;

public class Codeforces {
	FastScanner in;
	PrintWriter out;

	final long mod = (long)1e9 + 7;
	
	public void solve() throws IOException {
		int n = in.nextInt(), m = in.nextInt();
		long[][] dp = new long[n + 1][m + 1];
		long[][] sumdp = new long[n + 1][m + 1];
		long[][] sumoni = new long[n + 1][m + 1];
		for (int w = 2; w <= m; w++) {
			dp[1][w] = 1;
			sumdp[1][w] = (sumdp[1][w - 1] + dp[1][w]) % mod;
			sumoni[1][w] = (sumoni[1][w - 1] + dp[1][w] * (w - 1)) % mod;
		}
		for (int h = 2; h <= n; h++) {
			for (int w = 2; w <= m; w++) {
				dp[h][w] = ((sumdp[h - 1][w] * w - sumoni[h - 1][w]) % mod + mod) % mod;
				sumdp[h][w] = (sumdp[h][w - 1] + dp[h][w]) % mod;
				sumoni[h][w] = (sumoni[h][w - 1] + dp[h][w] * (w - 1)) % mod;
			}
		}
		long[][] sumdpw = new long[n + 1][m + 1];
		long[][] sumdpwh = new long[n + 1][m + 1];
		for (int h = 1; h <= n; h++) {
			for (int w = 2; w <= m; w++) {
				sumdpw[h][w] = (sumdpw[h][w - 1] + dp[h][w]) % mod;
				sumdpwh[h][w] = (sumdpwh[h - 1][w] + sumdpw[h][w]) % mod;
			}
		}
		for (int i = 0; i <= m; i++) {
			sumdpwh[0][i] = 1;
		}
		long[][] sumdpH = new long[n + 1][m + 1];
		for (int h = 1; h <= n; h++) {
			for (int w = 2; w <= m; w++) {
				sumdpH[h][w] = (sumdpH[h - 1][w] + sumdpwh[h][w]) % mod; 
			}
		}
		for (int i = 0; i <= m; i++) {
			sumdpH[0][i] = 1;
		}
		long[][] sumdpLen = new long[n + 1][m + 1];
		for (int h = 1; h <= n; h++) {
			for (int w = 2; w <= m; w++) {
				sumdpLen[h][w] = (sumdpLen[h - 1][w] + sumdpH[h][w]) % mod; 
			}
		}
		long ans = 0;
		for (int i = 0; i <= m; i++) {
			sumdpLen[0][i] = 1;
		}
		for (int p1 = 0; p1 <= n; p1++) {
			for (int w = 2; w <= m; w++) {
				long res = sumdpLen[n - p1][w - 1] * (m - w + 1); 
				res %= mod;
				res = (res * sumdpwh[p1][w - 1]) % mod;
				ans += res;
			}
		}
		out.println(ans);
	}

	public void run() {
		try {
			in = new FastScanner();
			out = new PrintWriter(System.out);

			solve();

			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	class FastScanner {
		BufferedReader br;
		StringTokenizer st;

		FastScanner() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}

		boolean hasNext() {
			while (st == null || !st.hasMoreTokens()) {
				try {
					String s = br.readLine();
					if (s == null) {
						return false;
					}
					st = new StringTokenizer(s);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			return true;
		}

		String next() {
			while (st == null || !st.hasMoreTokens()) {
				try {
					st = new StringTokenizer(br.readLine());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			return st.nextToken();
		}

		int nextInt() {
			return Integer.parseInt(next());
		}

		long nextLong() {
			return Long.parseLong(next());
		}

		double nextDouble() {
			return Double.parseDouble(next());
		}
	}

	public static void main(String[] arg) {
		new Codeforces().run();
	}
}