#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;
}

