#include <bits/stdc++.h>
#define endl '\n'
//#pragma GCC optimize ("O3")
//#pragma GCC target ("sse4")
using namespace std;
template<class T, class T2> inline int chkmax(T &x, const T2 &y) { return x < y ? x = y, 1 : 0; }
template<class T, class T2> inline int chkmin(T &x, const T2 &y) { return x > y ? x = y, 1 : 0; }
const int MAXN = 9;
int n, m;
string t[MAXN];
void read()
{
cin >> n >> m;
for(int i = 0; i < n; i++)
cin >> t[i];
}
int pop_cnt[1 << MAXN];
vector<int> check_masks[MAXN];
int broken_mask[MAXN];
int TMP_MASK;
bool ok(int cl, int mask, int prv, int need)
{
if(prv & mask)
return false;
if(mask & broken_mask[cl])
return false;
if(need & broken_mask[cl])
return false;
TMP_MASK = need;
for(int i: check_masks[cl])
if(pop_cnt[i & mask] >= 2)
return false;
else
{
if(pop_cnt[i & mask] == 0)
TMP_MASK |= i;
}
return true;
}
int64_t dp[MAXN][1 << MAXN][1 << MAXN];
int64_t rec(int pos, int last, int need)
{
if(pos == m)
return need == 0;
int64_t &memo = dp[pos][last][need];
if(memo != -1) return memo;
memo = 0;
for(int i = 0; i < (1 << n); i++)
if(ok(pos, i, last, need))
{
int n_mask = i | (last & ((1 << n) - 1 - broken_mask[pos]));
memo += rec(pos + 1, n_mask, TMP_MASK & ((1 << n) - 1 - n_mask));
}
return memo;
}
void solve()
{
for(int i = 1; i < (1 << MAXN); i++)
pop_cnt[i] = pop_cnt[i >> 1] + (i & 1);
for(int j = 0; j < m; j++)
{
int curr = 0;
for(int i = 0; i < n; i++)
if(t[i][j] == 'X')
{
broken_mask[j] |= (1 << i);
check_masks[j].push_back(curr);
curr = 0;
}
else
curr |= (1 << i);
check_masks[j].push_back(curr);
}
memset(dp, -1, sizeof(dp));
cout << rec(0, 0, 0) << endl;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
read();
solve();
return 0;
}
I2luY2x1ZGUgPGJpdHMvc3RkYysrLmg+CiNkZWZpbmUgZW5kbCAnXG4nCgovLyNwcmFnbWEgR0NDIG9wdGltaXplICgiTzMiKQovLyNwcmFnbWEgR0NDIHRhcmdldCAoInNzZTQiKQoKdXNpbmcgbmFtZXNwYWNlIHN0ZDsKdGVtcGxhdGU8Y2xhc3MgVCwgY2xhc3MgVDI+IGlubGluZSBpbnQgY2hrbWF4KFQgJngsIGNvbnN0IFQyICZ5KSB7IHJldHVybiB4IDwgeSA/IHggPSB5LCAxIDogMDsgfQp0ZW1wbGF0ZTxjbGFzcyBULCBjbGFzcyBUMj4gaW5saW5lIGludCBjaGttaW4oVCAmeCwgY29uc3QgVDIgJnkpIHsgcmV0dXJuIHggPiB5ID8geCA9IHksIDEgOiAwOyB9CmNvbnN0IGludCBNQVhOID0gOTsKCmludCBuLCBtOwpzdHJpbmcgdFtNQVhOXTsKCnZvaWQgcmVhZCgpCnsKCWNpbiA+PiBuID4+IG07Cglmb3IoaW50IGkgPSAwOyBpIDwgbjsgaSsrKQoJCWNpbiA+PiB0W2ldOwp9CgppbnQgcG9wX2NudFsxIDw8IE1BWE5dOwp2ZWN0b3I8aW50PiBjaGVja19tYXNrc1tNQVhOXTsKaW50IGJyb2tlbl9tYXNrW01BWE5dOwppbnQgVE1QX01BU0s7Cgpib29sIG9rKGludCBjbCwgaW50IG1hc2ssIGludCBwcnYsIGludCBuZWVkKQp7CglpZihwcnYgJiBtYXNrKQoJCXJldHVybiBmYWxzZTsKCglpZihtYXNrICYgYnJva2VuX21hc2tbY2xdKQoJCXJldHVybiBmYWxzZTsKCglpZihuZWVkICYgYnJva2VuX21hc2tbY2xdKQoJCXJldHVybiBmYWxzZTsKCglUTVBfTUFTSyA9IG5lZWQ7Cglmb3IoaW50IGk6IGNoZWNrX21hc2tzW2NsXSkKCQlpZihwb3BfY250W2kgJiBtYXNrXSA+PSAyKQoJCQlyZXR1cm4gZmFsc2U7CgkJZWxzZQoJCXsKCQkJaWYocG9wX2NudFtpICYgbWFza10gPT0gMCkKCQkJCVRNUF9NQVNLIHw9IGk7CgkJfQoKCXJldHVybiB0cnVlOwp9CgppbnQ2NF90IGRwW01BWE5dWzEgPDwgTUFYTl1bMSA8PCBNQVhOXTsKCmludDY0X3QgcmVjKGludCBwb3MsIGludCBsYXN0LCBpbnQgbmVlZCkKewoJaWYocG9zID09IG0pCgkJcmV0dXJuIG5lZWQgPT0gMDsKCglpbnQ2NF90ICZtZW1vID0gZHBbcG9zXVtsYXN0XVtuZWVkXTsKCWlmKG1lbW8gIT0gLTEpIHJldHVybiBtZW1vOwoKCW1lbW8gPSAwOwoJZm9yKGludCBpID0gMDsgaSA8ICgxIDw8IG4pOyBpKyspCgkJaWYob2socG9zLCBpLCBsYXN0LCBuZWVkKSkKCQl7CgkJCWludCBuX21hc2sgPSBpIHwgKGxhc3QgJiAoKDEgPDwgbikgLSAxIC0gYnJva2VuX21hc2tbcG9zXSkpOwoJCQltZW1vICs9IHJlYyhwb3MgKyAxLCBuX21hc2ssIFRNUF9NQVNLICYgKCgxIDw8IG4pIC0gMSAtIG5fbWFzaykpOwoJCX0KCglyZXR1cm4gbWVtbzsKfQoKdm9pZCBzb2x2ZSgpCnsKCWZvcihpbnQgaSA9IDE7IGkgPCAoMSA8PCBNQVhOKTsgaSsrKQoJCXBvcF9jbnRbaV0gPSBwb3BfY250W2kgPj4gMV0gKyAoaSAmIDEpOwoKCWZvcihpbnQgaiA9IDA7IGogPCBtOyBqKyspCgl7CgkJaW50IGN1cnIgPSAwOwoJCWZvcihpbnQgaSA9IDA7IGkgPCBuOyBpKyspCgkJCWlmKHRbaV1bal0gPT0gJ1gnKQoJCQl7CgkJCQlicm9rZW5fbWFza1tqXSB8PSAoMSA8PCBpKTsKCQkJCWNoZWNrX21hc2tzW2pdLnB1c2hfYmFjayhjdXJyKTsKCQkJCWN1cnIgPSAwOwoJCQl9CgkJCWVsc2UKCQkJCWN1cnIgfD0gKDEgPDwgaSk7CgoJCWNoZWNrX21hc2tzW2pdLnB1c2hfYmFjayhjdXJyKTsKCX0KCgltZW1zZXQoZHAsIC0xLCBzaXplb2YoZHApKTsKCWNvdXQgPDwgcmVjKDAsIDAsIDApIDw8IGVuZGw7Cn0KCmludCBtYWluKCkKewoJaW9zX2Jhc2U6OnN5bmNfd2l0aF9zdGRpbyhmYWxzZSk7CgljaW4udGllKE5VTEwpOwoKCXJlYWQoKTsKCXNvbHZlKCk7CglyZXR1cm4gMDsKfQoK