#include <iostream>
#include <cstring>
using namespace std;
const int N = 12, M = 1 << N;
bool st[M];
long long f[N][M];
int main (){
int n, m;
while (cin >> n >> m, n || m){
// 预处理,计算一列上哪些数可以用,这里用二进制表示可以,表达所有的情况。
// 为什么要这样预处理? 因为要保证从这个状态进到下一个状态前这个列要装满,不能不装满就走。
for (int i = 0; i < 1 << n; i ++){
int cnt = 0;
st[i] = true; //这里直接让他等于 true等等不行再改回去。
for (int j = 0; j < n; j++){
if (i >> j & 1){ //如果这个地方有放,判断从这个点往前数0是否偶数
if (cnt & 1){
cnt = 0; // 如果cnt 等于 1就说明之前的0的个数为奇数,非法
st[i] = false; // 既然非法就记下这个地方不能用;
}
}else cnt ++; //偶数序列的元素个数++;
//注意 上面的判断无法判断 0100这种情况,最大的0就退出了,所以要再加一个判断
}
if (cnt & 1) st[i] = false;
}
memset(f, 0, sizeof f); // memset是cstring库的函数,sizeof 是个运算符可以不用加()
f[0][0] = 1; // 第0列是不用的,因为要给算法初始化一个初值。
for (int i = 1; i <= m; i++)
for (int j = 0; j < 1 << n; j ++) // 这里把j定义为旧状态的行,k为新状态的行
for (int k = 0; k < 1 << n; k++){
// 这里是个关键点,把旧行伸出的方块合并到新列里面,同时加入新列的自己的元素;
if ((k & j) == 0 && st[j|k]) // st[j|k] 这样写可以同时判断是否为1
// 每个元素就是这样继承上一个元素,从刚刚f[0][0] = 1 开始。这个就是动态规划的精髓,状态转移方程
f[i][j] += f[i - 1][k];
}
cout << f[m][0] << endl; // 这里表示输出最后一列(m)且方块不伸出去情况有多少方案
}
return 0;
}