Problem: Snuke has a grid with H rows and W columns. The square at the i-th row and j-th column contains a character S_{i,j}.

He can perform the following two kinds of operation on the grid:

* Row-reverse: Reverse the order of the squares in a selected row.
* Column-reverse: Reverse the order of the squares in a selected column.



For example, reversing the 2-nd row followed by reversing the 4-th column will result as follows:

<image>

By performing these operations any number of times in any order, how many placements of characters on the grid can be obtained?

Constraints

* 1≦H,W≦200
* S_{i,j} is a lowercase English letter (`a`-`z`).

Input

The input is given from Standard Input in the following format:


H W
S_{1,1}S_{1,2}...S_{1,W}
S_{2,1}S_{2,2}...S_{2,W}
:
S_{H,1}S_{H,2}...S_{H,W}


Output

Print the number of placements of characters on the grid that can be obtained, modulo 1000000007 (=10^9+7).

Examples

Input

2 2
cf
cf


Output

6


Input

1 12
codefestival


Output

2

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define MAXN 205
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    while(c < '0' || c > '9') {
	if(c == '-') f = -1;
	c = getchar();
    }
    while(c >= '0' && c <= '9') {
	res = res * 10 +c - '0';
	c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) {
	out(x / 10);
    }
    putchar('0' + x % 10);
}
const int MOD = 1000000007;
int H,W;
char s[MAXN][MAXN];
int cnt[27],fa[MAXN * 2];
int inc(int a,int b) {
    return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
    return 1LL * a * b % MOD;
}
void update(int &x,int y) {
    x = inc(x,y);
}
int getfa(int x) {
    return x == fa[x] ? x : fa[x] = getfa(fa[x]);
}
int fpow(int x,int c) {
    int res = 1,t = x;
    while(c) {
	if(c & 1) res = mul(res,t);
	t = mul(t,t);
	c >>= 1;
    }
    return res;
}
void Solve() {
    read(H);read(W);
    for(int i = 1 ; i <= H ; ++i) {
	scanf("%s",s[i] + 1);
    }
    for(int i = 1 ; i <= H + W ; ++i) fa[i] = i;
    int ans = 1;
    if(H & 1) {
	bool f = 1;
	for(int j = 1 ; j <= W / 2 ; ++j) {
	    if(s[H / 2 + 1][j] != s[H / 2 + 1][W - j + 1]) {f = 0;break;}
	}
	if(!f) ans = mul(ans,2);
    }
    if(W & 1) {
	bool f = 1;
	for(int i = 1 ; i <= H / 2 ; ++i) {
	    if(s[i][W / 2 + 1] != s[H - i + 1][W / 2 + 1]) {f = 0;break;}
	}
	if(!f) ans = mul(ans,2);
    }
    int c = 0;
    for(int i = 1 ; i <= H / 2 ; ++i) {
	for(int j = 1 ; j <= W / 2 ; ++j) {
	    memset(cnt,0,sizeof(cnt));
	    cnt[s[i][j] - 'a']++;
	    cnt[s[H - i + 1][j] - 'a']++;
	    cnt[s[i][W - j + 1] - 'a']++;
	    cnt[s[H - i + 1][W - j + 1] - 'a']++;
	    bool f = 0;
	    int tmp = 24;
	    for(int k = 0 ; k < 26 ; ++k) {
		if(cnt[k] >= 2) {
		    f = 1;
		    if(cnt[k] == 2) tmp /= 2;
		    if(cnt[k] == 3) tmp /= 6;
		    if(cnt[k] == 4) tmp /= 24;
		}
	    }
	    if(!f) ans = mul(ans,tmp / 2);
	    else ans = mul(ans,tmp);
	    if(!f) {
		if(getfa(i) != getfa(j + H / 2)) {
		    ++c;
		    fa[getfa(i)] = getfa(j + H / 2);
		}
		
	    }
	}
    }
    ans = mul(ans,fpow(2,c));
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}