#include <bits/stdc++.h>
#define rep(i, n) for (rint i = 1; i <= (n); i ++)
#define re0(i, n) for (rint i = 0; i < (int) n; i ++)
#define travel(i, u) for (rint i = head[u]; i; i = e[i].nxt)
#define rint register int
using namespace std;
typedef long long lo;
template<typename tp> inline void read(tp &x) {
x = 0; char c = getchar(); int f = 0;
for (; c < '0' || c > '9'; f |= c == '-', c = getchar());
for (; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
if (f) x = -x;
}
namespace {
const int mo = 1e9 + 7;
inline int add(int x) {return x >= mo ? x - mo : x;}
inline int sub(int x) {return x < 0 ? x + mo : x;}
inline int mul(int x, int y) {return (long long) x * y % mo;}
inline int power(int a, int k = mo - 2) {
int ans = 1;
for (; k; k >>= 1, a = mul(a, a))
if (k & 1) ans = mul(ans, a);
return ans;
}
}
namespace G {
vector <int> pre;
int n;
inline void init(int _n) {
n = _n;
pre.resize(n + 1);
rep (i, n) pre[i] = i;
}
inline int find(int x) {
return pre[x] == x ? x : pre[x] = find(pre[x]);
}
inline void make(int x, int y) {
assert(x <= n); assert(y <= n);
pre[find(x)] = find(y);
}
}
const int N = 233;
int n, m;
char s[N][N];
int main(void) {
read(n); read(m);
G::init(n / 2 + m / 2);
rep (i, n) scanf("%s", s[i] + 1);
int ans = 1;
if (n & 1) {
for (int j = 1; j <= m / 2; j++)
if (s[n / 2 + 1][j] != s[n / 2 + 1][m + 1 - j]) {
ans = mul(ans, 2);
break;
}
}
if (m & 1) {
for (int i = 1; i <= n / 2; i++)
if (s[i][m / 2 + 1] != s[n + 1 - i][m / 2 + 1]) {
ans = mul(ans, 2);
break;
}
}
for (int i = 1; i <= n / 2; i++)
for (int j = 1; j <= m / 2; j++) {
int a[] = {s[i][j], s[n - i + 1][j], s[n - i + 1][m - j + 1], s[i][m - j + 1]};
sort(a, a + 4);
int cnt = 0;
do {
++cnt;
} while (next_permutation(a, a + 4));
cnt == 24 ? G::make(i, j + n / 2), ans = mul(ans, 12) : ans = mul(ans, cnt);
}
int o = n / 2 + m / 2;
rep (i, n / 2 + m / 2) o -= G::find(i) == i;
ans = mul(ans, power(2, o));
cout << ans << "\n";
}