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<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<cassert>
#define PB push_back
#define MP make_pair
#define sz(v) (in((v).size()))
#define forn(i,n) for(in i=0;i<(n);++i)
#define forv(i,v) forn(i,sz(v))
#define fors(i,s) for(auto i=(s).begin();i!=(s).end();++i)
#define all(v) (v).begin(),(v).end()
using namespace std;
typedef long long in;
typedef vector<in> VI;
typedef vector<VI> VVI;
vector<string> bd;
const in mdl=1000000007;
VI rcon,ccon;
VVI bas;
queue<in> rrm,crm;
in totrm=0;
in sm=1;
void rmr(in u){
  in s=0;
  forv(i,bas[u]){
    s+=bas[u][i];
    if(bas[u][i]){
      --ccon[i];
      if(ccon[i]<=1 && ccon[i]>=0){
	ccon[i]=-1;
	++totrm;
	crm.push(i);
      }
    }
    bas[u][i]=0;
  }
  if(s)
    sm*=2;
  sm%=mdl;
}
void rmc(in u){
  in s=0;
  forv(i,bas){
    s+=bas[i][u];
    if(bas[i][u]){
      --rcon[i];
      if(rcon[i]<=1 && rcon[i]>=0){
	rcon[i]=-1;
	++totrm;
	rrm.push(i);
      }
    }
    bas[i][u]=0;
  }
  if(s)
    sm*=2;
  sm%=mdl;
}
int main(){
  ios::sync_with_stdio(0);
  cin.tie(0);
  in h,w;
  cin>>h>>w;
  bd.resize(h);
  forn(i,h)
    cin>>bd[i];
  if(h%2){
    string s=bd[h/2];
    reverse(all(s));
    if(s!=bd[h/2])
      sm*=2;
  }
  if(w%2){
    string s(h,'a');
    forn(i,h)
      s[i]=bd[i][w/2];
    reverse(all(s));
    bool dif=0;
    forn(i,h)
      if(s[i]!=bd[i][w/2])
	dif=1;
    if(dif)
      sm*=2;
  }
  bas.resize(h/2,VI(w/2));
  rcon.resize(h/2);
  ccon.resize(w/2);
  forn(i,h/2){
    forn(j,w/2){
      string s;
      s.PB(bd[i][j]);
      s.PB(bd[h-1-i][j]);
      s.PB(bd[i][w-1-j]);
      s.PB(bd[h-1-i][w-1-j]);
      sort(all(s));
      in pm=24;
      in csz=1;
      forn(z,4){
	if(z==0 || s[z]!=s[z-1]){
	  for(in zz=1;zz<=csz;++zz)
	    pm/=zz;
	  csz=1;
	  continue;
	}
	++csz;
      }
      for(in zz=1;zz<=csz;++zz)
	pm/=zz;
      if(pm==24){
	++rcon[i];
	++ccon[j];
	bas[i][j]=1;
	pm/=2;
      }
      sm*=pm;
      sm%=mdl;
    }
  }
  forv(i,rcon){
    if(rcon[i]<=1){
      rcon[i]=-1;
      ++totrm;
      rrm.push(i);
    }
  }
  forv(i,ccon){
    if(ccon[i]<=1){
      ccon[i]=-1;
      ++totrm;
      crm.push(i);
    }
  }
  in u;
  while(!rrm.empty() || !crm.empty()){
    if(!rrm.empty()){
      u=rrm.front();
      rrm.pop();
      rmr(u);
    }
    else{
      u=crm.front();
      crm.pop();
      rmc(u);
    }
  }
  in lft=h/2+w/2-totrm-1;
  forn(i,lft)
    sm=sm*2%mdl;
  cout<<sm<<endl;
  return 0;
}