#pragma GCC optimize ("Ofast")
#pragma GCC optimize ("unroll-loops")
#pragma GCC target ("avx")
#include <cassert>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
using Int = long long;
template <class T1, class T2> ostream &operator<<(ostream &os, const pair<T1, T2> &a) { return os << "(" << a.first << ", " << a.second << ")"; };
template <class T> void pv(T a, T b) { for (T i = a; i != b; ++i) cerr << *i << " "; cerr << endl; }
template <class T> bool chmin(T &t, const T &f) { if (t > f) { t = f; return true; } return false; }
template <class T> bool chmax(T &t, const T &f) { if (t < f) { t = f; return true; } return false; }
constexpr int LIM = 105;
int cache[LIM][LIM];
int uf[LIM * LIM];
int root(int u) {
return (uf[u] < 0) ? u : (uf[u] = root(uf[u]));
}
bool connect(int u, int v) {
u = root(u);
v = root(v);
if (u == v) return false;
if (uf[u] > uf[v]) swap(u, v);
uf[u] += uf[v];
uf[v] = u;
return true;
}
int qsLen[2];
pair<int, int> qs[2][4 * LIM];
__int128 board[LIM];
int main() {
for (int m = 0; m < LIM; ++m) for (int n = 0; n < LIM; ++n) {
cache[m][n] = -1;
}
int numCases;
scanf("%d", &numCases);
for (int caseId = 1; caseId <= numCases; ++caseId) {
cerr << "==== Case #" << caseId << " ====" << endl;
int M, N;
scanf("%d%d", &M, &N);
if (M > N) {
swap(M, N);
}
if (cache[M][N] == -1) {
int ans = 0;
vector<pair<int, int>> ps;
for (int y = 1; y < N; ++y) ps.emplace_back(1, y);
for (int x = 1; x < M; ++x) ps.emplace_back(x, N);
for (int y = N; y > 1; --y) ps.emplace_back(M, y);
for (int x = M; x > 1; --x) ps.emplace_back(x, 1);
const int psLen = ps.size();
for (int i = 1; i <= psLen; ++i) for (int j = i + 1; j <= psLen; ++j) {
vector<pair<int, int>> qsF[2], qsB[2];
for (int k = 0; k < psLen; ++k) {
if (((ps[k].first == 1 || ps[k].first == M) && (ps[k].second == 1 || ps[k].second == N)) ||
k == j % psLen || k == i - 1 || k == i || k == j - 1) {
for (int d = -M; d <= +M; ++d) {
const int s = ((i <= k && k < j) ? 1 : 0) ^ (d & 1);
{
const int xx = ps[k].first + d;
const int yy = ps[k].second + d;
if (1 <= xx && xx <= M && 1 <= yy && yy <= N) {
qsF[s].emplace_back(xx, yy);
}
}
{
const int xx = ps[k].first + d;
const int yy = ps[k].second - d;
if (1 <= xx && xx <= M && 1 <= yy && yy <= N) {
qsB[s].emplace_back(xx, yy);
}
}
}
}
}
for (int s = 0; s < 2; ++s) {
sort(qsF[s].begin(), qsF[s].end());
sort(qsB[s].begin(), qsB[s].end());
qsF[s].erase(unique(qsF[s].begin(), qsF[s].end()), qsF[s].end());
qsB[s].erase(unique(qsB[s].begin(), qsB[s].end()), qsB[s].end());
qsLen[s] = set_intersection(qsF[s].begin(), qsF[s].end(), qsB[s].begin(), qsB[s].end(), qs[s]) - qs[s];
}
board[1] = 0;
for (int k = 0; k < N; ++k) {
if (i <= k && k < j) {
board[1] |= (__int128)1 << (1 + k);
}
}
board[1] |= ((board[1] >> 1) & 1) ^ 1;
board[1] |= (((board[1] >> N) & 1) ^ 1) << (N + 1);
board[0] = board[1] ^ (((__int128)1 << (N + 2)) - 1);
for (int l00 = 0; l00 < qsLen[0]; ++l00) for (int l01 = l00 + 1; l01 < qsLen[0]; ++l01)
for (int l10 = 0; l10 < qsLen[1]; ++l10) for (int l11 = l10 + 1; l11 < qsLen[1]; ++l11)
{
for (int x = 1; x <= M; ++x) {
const __int128 bU = board[x - 1];
const __int128 bL = board[x] << 1;
const __int128 bR = board[x] >> 1;
board[x + 1] = (bU ^ bL ^ bR) & (((__int128)1 << (N + 1)) - 2);
if (qs[0][l00].first == x) {
if (board[x] & (__int128)1 << qs[0][l00].second) goto failed;
board[x + 1] ^= (__int128)1 << qs[0][l00].second;
}
if (qs[0][l01].first == x) {
if (board[x] & (__int128)1 << qs[0][l01].second) goto failed;
board[x + 1] ^= (__int128)1 << qs[0][l01].second;
}
if (qs[1][l10].first == x) {
if (!(board[x] & (__int128)1 << qs[1][l10].second)) goto failed;
board[x + 1] ^= (__int128)1 << qs[1][l10].second;
}
if (qs[1][l11].first == x) {
if (!(board[x] & (__int128)1 << qs[1][l11].second)) goto failed;
board[x + 1] ^= (__int128)1 << qs[1][l11].second;
}
if (bU & bL & bR & board[x + 1]) {
goto failed;
}
if (~(bU | bL | bR | board[x + 1]) & (((__int128)1 << (N + 1)) - 2)) {
goto failed;
}
board[x + 1] |= ((board[x + 1] >> 1) & 1) ^ 1;
board[x + 1] |= (((board[x + 1] >> N) & 1) ^ 1) << (N + 1);
}
if ((board[M] ^ (((__int128)1 << (N + 2)) - 1)) != board[M + 1]) {
goto failed;
}
for (int k = 0; k < psLen; ++k) {
if ((bool)(board[ps[k].first] & (__int128)1 << ps[k].second) != (i <= k && k < j)) {
goto failed;
}
}
fill(uf, uf + M * N, -1);
for (int x = 1; x <= M; ++x) for (int y = 1; y <= N; ++y) {
if (x > 1 && (bool)(board[x - 1] & (__int128)1 << y) == (bool)(board[x] & (__int128)1 << y)) {
if (!connect((x - 1 - 1) * N + (y - 1), (x - 1) * N + (y - 1))) {
goto failed;
}
}
if (y > 1 && (bool)(board[x] & (__int128)1 << (y - 1)) == (bool)(board[x] & (__int128)1 << y)) {
if (!connect((x - 1) * N + (y - 1 - 1), (x - 1) * N + (y - 1))) {
goto failed;
}
}
}
++ans;
// cout<<"solution"<<endl;for(int x=1;x<=M;++x){for(int y=1;y<=N;++y){cout<<(int)((board[x]>>y)&1);}cout<<endl;}
failed:{}
}
}
ans *= 2;
cache[M][N] = ans;
}
printf("Case #%d: %d\n", caseId, cache[M][N]);
fflush(stdout);
}
return 0;
}