import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer in = new StreamTokenizer(br);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
while (in.nextToken() != StreamTokenizer.TT_EOF) {
int n = (int) in.nval;
in.nextToken();
int m = (int) in.nval;
long[][] dp = new long[n + 1][m + 1];
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= m; j++) {
dp[i][j] = -1;
}
}
out.println(compute2(n, m, dp));
}
out.flush();
out.close();
br.close();
}
// 记忆化搜索动态规划
private static long compute(int n, int m, long[][] dp) {
if (n == 0) {
return 1;
}
if (m == 0) {
return 0;
}
if (dp[n][m] != -1) {
return dp[n][m];
}
long ans = 0;
for (int i = 0; i < n; i++) {
ans = (ans + compute(i, m - 1, dp) * compute(n - i - 1, m - 1,
dp)) % 1000000007;
}
dp[n][m] = ans;
return ans;
}
// 严格位置依赖的动态规划
private static long compute2(int n, int m, long[][] dp) {
for (int j = 0; j <= n; j++) {
dp[j][0] = 0;
}
for(int i=0; i<= m; i++){
dp[0][i] = 1;
}
for(int i=1; i<= n; i++){
for(int j=1; j<=m; j++){
dp[i][j] = 0;
for(int k=0; k < i; k++) {
dp[i][j] = (dp[i][j] + dp[k][j-1] * dp[i-k-1][j-1]%1000000007)%1000000007;
}
}
}
return dp[n][m];
}
}