#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <fstream>
#include <complex>

#define pb push_back
#define pf push_front
#define mp make_pair
#define REP(i, a, b)     for (int i = int(a); i <= int(b); i++)
#define SET(p) memset(p, -1, sizeof(p))
#define CLR(p) memset(p, 0, sizeof(p))
#define all(c) c.begin(), c.end()
#define tr(container, it) for(typeof(container.begin()) it=container.begin(); it!=container.end(); it++)
#define present(container, element) (container.find(element)!=container.end())
#define cpresent(container, element) (find(all(container), element)!=container.end())
#define sz(a) int((a).size())

using namespace std;

typedef long long ll;
typedef pair<int, int> ii;
typedef vector<ii> vii;
typedef vector<int> vi;
typedef vector<vi> vvi;

const double PI = 2.0*acos(0.0);
const double EPS = 1e-9;
const int MOD = 1000000009;
const int INF = 1000000000;
const ll LINF = 1000000000000000000LL;

vector<string> vs;
ii arr[260][260];
map<string, ii> mapa;
int n, m;
long long pdcol[260], pdrow[260];

void debug() {
	REP (i, 1, n) {
		REP (j, 1, m) printf("(%d,%d) ", arr[i][j].first, arr[i][j].second);
		puts("");
	}
}

void init() {
	mapa["........."]=mp(0, 3), mapa["....O...."]=mp(1, 3), mapa["..O...O.."]=mp(2, 1), mapa["O.......O"]=mp(2, 2), mapa["..O.O.O.."]=mp(3, 1);
	mapa["O...O...O"]=mp(3, 2), mapa["O.O...O.O"]=mp(4, 3), mapa["O.O.O.O.O"]=mp(5, 3), mapa["O.OO.OO.O"]=mp(6, 1), mapa["OOO...OOO"]=mp(6, 2);
	string str;
	cin>>n>>m;
	REP (i, 1, 4*n+1) cin>>str, vs.pb(str);
	REP (i, 1, n) REP (j, 1, m) {
		str="";
		REP (k, 1, 3) str+=vs[4*(i-1)+k].substr(4*(j-1)+1, 3);
		arr[i][j]=mapa[str];
	}
}

ll uni(int c) {
	if (n%2) return 0LL;
	ll ret=1LL;
	REP (i, 1, n) ret&=arr[i][c].second&1;
	return ret;
}

ll dupla(int c) {
	REP (i, 1, n) {
		pdrow[i]=1LL*(arr[i][c-1].second&2)/2LL*(arr[i][c].second&2)/2LL*pdrow[i-1];
		//cout<<i<<' '<<c<<' '<<pdrow[i]<<endl;
		if (i>1) pdrow[i]=(pdrow[i]+1LL*(arr[i-1][c-1].second&1)*(arr[i-1][c].second&1)*(arr[i][c-1].second&1)*(arr[i][c].second&1)*pdrow[i-2]%MOD)%MOD;
		//cout<<i<<' '<<c<<' '<<pdrow[i]<<endl;
	}
	pdrow[n]=(pdrow[n]-1LL*uni(c)*uni(c-1)+MOD)%MOD;
	return pdrow[n];
}

int main() {
	init(), pdcol[0]=pdrow[0]=1LL;
	//debug();
	REP (i, 1, m) {
		pdcol[i]=1LL*uni(i)*pdcol[i-1];
		if (i>1) pdcol[i]=(pdcol[i]+1LL*dupla(i)*pdcol[i-2]%MOD)%MOD;
		/*cout<<i<<' '<<uni(i)<<endl;
		cout<<i<<' '<<dupla(i)<<endl;
		cout<<i<<' '<<pdcol[i]<<endl;*/
	}
	cout<<pdcol[m]<<endl;
    return 0;
}


#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <fstream>
#include <complex>

#define pb push_back
#define pf push_front
#define mp make_pair
#define REP(i, a, b)     for (int i = int(a); i <= int(b); i++)
#define SET(p) memset(p, -1, sizeof(p))
#define CLR(p) memset(p, 0, sizeof(p))
#define all(c) c.begin(), c.end()
#define tr(container, it) for(typeof(container.begin()) it=container.begin(); it!=container.end(); it++)
#define present(container, element) (container.find(element)!=container.end())
#define cpresent(container, element) (find(all(container), element)!=container.end())
#define sz(a) int((a).size())

using namespace std;

typedef long long ll;
typedef pair<int, int> ii;
typedef vector<ii> vii;
typedef vector<int> vi;
typedef vector<vi> vvi;

const double PI = 2.0*acos(0.0);
const double EPS = 1e-9;
const int MOD = 1000000009;
const int INF = 1000000000;
const ll LINF = 1000000000000000000LL;

vector<string> vs;
ii arr[260][260];
map<string, ii> mapa;
int n, m;
long long pdcol[260], pdrow[260];

void debug() {
    REP (i, 1, n) {
        REP (j, 1, m) printf("(%d,%d) ", arr[i][j].first, arr[i][j].second);
        puts("");
    }
}

void init() {
    mapa["........."]=mp(0, 3), mapa["....O...."]=mp(1, 3), mapa["..O...O.."]=mp(2, 1), mapa["O.......O"]=mp(2, 2), mapa["..O.O.O.."]=mp(3, 1);
    mapa["O...O...O"]=mp(3, 2), mapa["O.O...O.O"]=mp(4, 3), mapa["O.O.O.O.O"]=mp(5, 3), mapa["O.OO.OO.O"]=mp(6, 1), mapa["OOO...OOO"]=mp(6, 2);
    string str;
    cin>>n>>m;
    REP (i, 1, 4*n+1) cin>>str, vs.pb(str);
    REP (i, 1, n) REP (j, 1, m) {
        str="";
        REP (k, 1, 3) str+=vs[4*(i-1)+k].substr(4*(j-1)+1, 3);
        arr[i][j]=mapa[str];
    }
}

ll uni(int c) {
    if (n%2) return 0LL;
    ll ret=1LL;
    REP (i, 1, n) ret&=arr[i][c].second&1;
    return ret;
}

ll dupla(int c) {
    REP (i, 1, n) {
        pdrow[i]=1LL*(arr[i][c-1].second&2)/2LL*(arr[i][c-1].second&2)/2LL*pdrow[i-1];
        if (i>1) pdrow[i]=(pdrow[i]+1LL*(arr[i-1][c-1].second&1)*(arr[i-1][c].second&1)*(arr[i][c-1].second&1)*(arr[i][c].second&1)*pdrow[i-2]%MOD)%MOD;
        //cout<<i<<' '<<c<<' '<<pdrow[i]<<endl;
    }
    pdrow[n]=(pdrow[n]-1LL*uni(c)*uni(c-1)*pdcol[c-2]+MOD)%MOD;
    return pdrow[n];
}

int main() {
    init(), pdcol[0]=pdrow[0]=1LL;
    //debug();
    REP (i, 1, m) {
        pdcol[i]=1LL*uni(i)*pdcol[i-1];
        if (i>1) pdcol[i]=(pdcol[i]+1LL*dupla(i)*pdcol[i-2]%MOD)%MOD;
        //cout<<i<<' '<<uni(i)<<endl;
        //cout<<i<<' '<<dupla(i)<<endl;
        //cout<<i<<' '<<pdcol[i]<<endl;
    }
    cout<<pdcol[m]<<endl;
    return 0;
}


#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <numeric>
#include <complex>
#ifdef IGEL_ACM
#include <ctime>
#endif

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> pnt;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector <vector < pair <int, int> > > VVP;

#define FI(i,a) for (int i=0; i<(a); ++i)
#define RFI(i,a) for (int i=(a); i>=0; --i)
#define FOR(i,s,e) for (int i=(s); i<(e); ++i)
#define RFOR(i,e,s) for (int i=(e); i>=s; --i)
#define MEMS(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define mp make_pair
#define ALL(a) a.begin(),a.end()
#define ISIN(s,a) (s.find(a)!=s.end())
#define sqr(a) ((a)*(a))
#define abs(a) (((a)>0)?(a):(-(a)))
#define CPY(a, b) memcpy(a, b, sizeof(a))

#define dout(a) cerr << a << endl;
#define sout(a) cerr << a << "  ";

const double pi = 3.14159265358979323846264338327950288419716939937511;
const double eps = 1e-9;

char ch_ch_ch[1<<20];
string gs() {scanf("%s",ch_ch_ch); return string(ch_ch_ch);}
string gl() {gets(ch_ch_ch); return string(ch_ch_ch);}

int n,m;
int a[300][300];
// 1 - hor
// 2 - ver
// 3 - both
string ss[3];

map <string , int> strmap;

const int mod=1e9+7;

int f(int k)
{
    if (n&1) {FI(i,n) if (a[i][k]==1) return 0; return 1;}
    return 0;
}

int dpq[300];

int Q(int k, int p)
{
    if (k<0) return 0;
    if (p==n) return 1;
    if (dpq[p]!=-1) return dpq[p];
    int res=0;
    if (a[p][k]!=2 && a[p][k+1]!=2) res=(res+Q(k,p+1))%mod;
    if (p<n-1 && a[p][k]!=1 && a[p+1][k]!=1 && a[p][k+1]!=1 && a[p+1][k+1]!=1) res=(res+Q(k,p+2))%mod;
    return dpq[p]=res;
}

int q(int k)
{
    MEMS(dpq,-1);
    return Q(k,0);
}

int dpr[300];

int R(int k)
{
    if (k<=0) return 1;
    if (dpr[k]!=-1) return dpr[k];
    return dpr[k]=((LL)R(k-1)*f(k-1)+(LL)R(k-2)*1ll*q(k-2)-(LL)R(k-2)*f(k-1)*f(k-2))%mod;
}

void solution()
{
    strmap["O.O.O.O.O"]=3;
    strmap["....O...."]=3;
    strmap["O.O...O.O"]=3;
    strmap["........."]=3;

    strmap["..O...O.."]=2;
    strmap["..O.O.O.."]=2;
    strmap["O.OO.OO.O"]=2;

    strmap["O.......O"]=1;
    strmap["O...O...O"]=1;
    strmap["OOO...OOO"]=1;

    cin >> n >> m;
    gl();

    FI(i,n)
    {
	gl();
	FI(k,3) ss[k]=gl();
	FI(j,m)
	{
	    int p=1+4*j;
	    string s="";
	    FI(k,3) s+=ss[k].substr(p,3);
	    a[i][j]=strmap[s];
	}
    }
    MEMS(dpr,-1);
    cout << R(m) << endl;
}

int main()
{
#ifdef IGEL_ACM
	freopen("sample.in", "r", stdin);
	//freopen("out.txt", "w", stdout);
	clock_t beg_time = clock();
#else
	//freopen("k9.in", "r", stdin);
	//freopen("k9.out", "w", stdout);
#endif

	solution();

#ifdef IGEL_ACM
	fprintf(stderr,"Time: %.3lf\n",1.0*(clock()-beg_time)/CLOCKS_PER_SEC);
#endif

    return 0;
}


#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <numeric>
#include <complex>
#ifdef IGEL_ACM
#include <ctime>
#endif

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> pnt;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector <vector < pair <int, int> > > VVP;

#define FI(i,a) for (int i=0; i<(a); ++i)
#define RFI(i,a) for (int i=(a); i>=0; --i)
#define FOR(i,s,e) for (int i=(s); i<(e); ++i)
#define RFOR(i,e,s) for (int i=(e); i>=s; --i)
#define MEMS(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define mp make_pair
#define ALL(a) a.begin(),a.end()
#define ISIN(s,a) (s.find(a)!=s.end())
#define sqr(a) ((a)*(a))
#define abs(a) (((a)>0)?(a):(-(a)))
#define CPY(a, b) memcpy(a, b, sizeof(a))

#define dout(a) cerr << a << endl;
#define sout(a) cerr << a << "  ";

const double pi = 3.14159265358979323846264338327950288419716939937511;
const double eps = 1e-9;

char ch_ch_ch[1<<20];
string gs() {scanf("%s",ch_ch_ch); return string(ch_ch_ch);}
string gl() {gets(ch_ch_ch); return string(ch_ch_ch);}

int n,m;
int a[300][300];
// 1 - hor
// 2 - ver
// 3 - both
string ss[3];

map <string , int> strmap;

const int mod=1e9+7;

int f(int k)
{
    if (k<0 || (n&1)) return 0;
    FI(i,n) if (a[i][k]==1) return 0;
    return 1;
}

int dpq[300];

int Q(int k, int p)
{
    if (k<0) return 0;
    if (p==n) return 1;
    if (dpq[p]!=-1) return dpq[p];
    int res=0;
    if (a[p][k]!=2 && a[p][k+1]!=2) res=(res+Q(k,p+1))%mod;
    if (p<n-1 && a[p][k]!=1 && a[p+1][k]!=1 && a[p][k+1]!=1 && a[p+1][k+1]!=1) res=(res+Q(k,p+2))%mod;
    return dpq[p]=res;
}

int q(int k)
{
    MEMS(dpq,-1);
    return Q(k,0);
}

int dpr[300];

int R(int k)
{
    if (k<=0) return 1;
    if (dpr[k]!=-1) return dpr[k];
    return dpr[k]=((LL)R(k-1)*f(k-1)+(LL)R(k-2)*1ll*q(k-2)-(LL)R(k-2)*f(k-1)*f(k-2))%mod;
}

void solution()
{
    strmap["O.O.O.O.O"]=3;
    strmap["....O...."]=3;
    strmap["O.O...O.O"]=3;
    strmap["........."]=3;

    strmap["..O...O.."]=2;
    strmap["..O.O.O.."]=2;
    strmap["O.OO.OO.O"]=2;

    strmap["O.......O"]=1;
    strmap["O...O...O"]=1;
    strmap["OOO...OOO"]=1;

    cin >> n >> m;
    gl();

    FI(i,n)
    {
	gl();
	FI(k,3) ss[k]=gl();
	FI(j,m)
	{
	    int p=1+4*j;
	    string s="";
	    FI(k,3) s+=ss[k].substr(p,3);
	    a[i][j]=strmap[s];
	}
    }
    MEMS(dpr,-1);
    cout << R(m) << endl;
   // FI(i,m+1) dout(i << ' ' << dpr[i]);
}

int main()
{
#ifdef IGEL_ACM
	freopen("sample.in", "r", stdin);
	//freopen("out.txt", "w", stdout);
	clock_t beg_time = clock();
#else
	//freopen("k9.in", "r", stdin);
	//freopen("k9.out", "w", stdout);
#endif

	solution();

#ifdef IGEL_ACM
	fprintf(stderr,"Time: %.3lf\n",1.0*(clock()-beg_time)/CLOCKS_PER_SEC);
#endif

    return 0;
}


#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
using namespace std;

#define modulo 1000000007

int dp[300];
int colone[300];
int coltwo[300];
int grid[300][300];
char readin[2000];

int calcColumnTwo( int j, int i ){
	if ( dp[i] != -1 )
		return dp[i];
	int ret = 0;
	if ( !( grid[i][j] / 10 == 1 || grid[i][j+1] / 10 == 1 ) )
		ret += calcColumnTwo( j, i + 1 );
	if ( !( grid[i][j] > 20 || grid[i][j+1] > 20 || grid[i+1][j] > 20 || grid[i+1][j+1] > 20 ) )
		ret += calcColumnTwo( j, i + 2 );
	ret %= modulo;

	return dp[i] = ret;
}

int calc( int col ){
	if ( dp[col] != -1 )
		return dp[col];
	long long ret = 0;
	ret += 1LL * colone[col] * calc( col + 1 );
	ret += 1LL * coltwo[col+1] * calc( col + 2 );
	ret %= modulo;

	return dp[col] = ret;
}

main(){
	int n, m;
	int i, j;
	int code[513];

	scanf ( "%d %d", &n, &m );
	code[0] = 0;
	code[16] = 1;
	code[257] = 22;
	code[68] = 12;
	code[84] = 13;
	code[273] = 23;
	code[325] = 4;
	code[341] = 5;
	code[455] = 26;
	code[365] = 16;

	memset ( grid, 0, sizeof ( grid ) );
	for ( i = 0; i < n; i ++ ){
		scanf ( "%s", readin );
		scanf ( "%s", readin );
		for ( j = 0; j < m; j ++ ){
			if ( readin[ j * 4 + 1 ] == 'O' )
				grid[i][j] |= 256;
			if ( readin[ j * 4 + 2 ] == 'O' )
				grid[i][j] |= 128;
			if ( readin[ j * 4 + 3 ] == 'O' )
				grid[i][j] |=  64;
		}
		scanf ( "%s", readin );
		for ( j = 0; j < m; j ++ ){
			if ( readin[ j * 4 + 1 ] == 'O' )
				grid[i][j] |=  32;
			if ( readin[ j * 4 + 2 ] == 'O' )
				grid[i][j] |=  16;
			if ( readin[ j * 4 + 3 ] == 'O' )
				grid[i][j] |=   8;
		}
		scanf ( "%s", readin );
		for ( j = 0; j < m; j ++ ){
			if ( readin[ j * 4 + 1 ] == 'O' )
				grid[i][j] |=   4;
			if ( readin[ j * 4 + 2 ] == 'O' )
				grid[i][j] |=   2;
			if ( readin[ j * 4 + 3 ] == 'O' )
				grid[i][j] |=   1;
		}
		for ( j = 0; j < m; j ++ )
			grid[i][j] = code[ grid[i][j] ];
	}
	memset ( colone, 0, sizeof ( colone ) );
	for ( j = 0; j < m; j ++ ){
		for ( i = 0; i < n; i += 2 )
			if ( grid[i][j] > 20 || grid[i+1][j] > 20 )
				break;
		if ( i == n )
			colone[j] = 1;
	}
	memset ( coltwo, 0, sizeof ( coltwo ) );
	for ( j = 1; j < m; j ++ ){
		memset ( dp, -1, sizeof ( dp ) );
		dp[n] = 1;	dp[ n + 1 ] = 0;
		coltwo[j] = calcColumnTwo( j - 1, 0 );
		if ( n % 2 == 0 ){
			coltwo[j] --;
			if ( coltwo[j] < 0 )
				coltwo[j] += modulo;
		}
	}
	memset ( dp, -1, sizeof ( dp ) );
	dp[m] = 1;	dp[ m + 1 ] = 0;
	cout << calc( 0 ) << endl;
//	for ( i = 0; i < m; i ++ )	cout << colone[i] << " ";	cout << endl;
//	for ( i = 0; i < m; i ++ )	cout << coltwo[i] << " ";	cout << endl;
//	cin >> i;
	return 0;
}


#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
using namespace std;

#define modulo 1000000007

int dp[300];
int colone[300];
int coltwo[300];
int grid[300][300];
char readin[2000];

int calcColumnTwo( int j, int i ){
	if ( dp[i] != -1 )
		return dp[i];
	int ret = 0;
	if ( !( grid[i][j] / 10 == 1 || grid[i][j+1] / 10 == 1 ) )
		ret += calcColumnTwo( j, i + 1 );
	if ( !( grid[i][j] > 20 || grid[i][j+1] > 20 || grid[i+1][j] > 20 || grid[i+1][j+1] > 20 ) )
		ret += calcColumnTwo( j, i + 2 );
	ret %= modulo;

	return dp[i] = ret;
}

int calc( int col ){
	if ( dp[col] != -1 )
		return dp[col];
	long long ret = 0;
	ret += 1LL * colone[col] * calc( col + 1 );
	ret += 1LL * coltwo[col+1] * calc( col + 2 );
	ret %= modulo;

	return dp[col] = ret;
}

main(){
	int n, m;
	int i, j;
	int code[513];

	scanf ( "%d %d", &n, &m );
	code[0] = 0;
	code[16] = 1;
	code[257] = 22;
	code[68] = 12;
	code[84] = 13;
	code[273] = 23;
	code[325] = 4;
	code[341] = 5;
	code[455] = 26;
	code[365] = 16;

	memset ( grid, 0, sizeof ( grid ) );
	for ( i = 0; i < n; i ++ ){
		scanf ( "%s", readin );
		scanf ( "%s", readin );
		for ( j = 0; j < m; j ++ ){
			if ( readin[ j * 4 + 1 ] == 'O' )
				grid[i][j] |= 256;
			if ( readin[ j * 4 + 2 ] == 'O' )
				grid[i][j] |= 128;
			if ( readin[ j * 4 + 3 ] == 'O' )
				grid[i][j] |=  64;
		}
		scanf ( "%s", readin );
		for ( j = 0; j < m; j ++ ){
			if ( readin[ j * 4 + 1 ] == 'O' )
				grid[i][j] |=  32;
			if ( readin[ j * 4 + 2 ] == 'O' )
				grid[i][j] |=  16;
			if ( readin[ j * 4 + 3 ] == 'O' )
				grid[i][j] |=   8;
		}
		scanf ( "%s", readin );
		for ( j = 0; j < m; j ++ ){
			if ( readin[ j * 4 + 1 ] == 'O' )
				grid[i][j] |=   4;
			if ( readin[ j * 4 + 2 ] == 'O' )
				grid[i][j] |=   2;
			if ( readin[ j * 4 + 3 ] == 'O' )
				grid[i][j] |=   1;
		}
		for ( j = 0; j < m; j ++ )
			grid[i][j] = code[ grid[i][j] ];
	}
	memset ( colone, 0, sizeof ( colone ) );
	for ( j = 0; j < m; j ++ ){
		for ( i = 0; i < n; i += 2 )
			if ( grid[i][j] > 20 || grid[i+1][j] > 20 )
				break;
		if ( i == n )
			colone[j] = 1;
	}
	memset ( coltwo, 0, sizeof ( coltwo ) );
	for ( j = 1; j < m; j ++ ){
		memset ( dp, -1, sizeof ( dp ) );
		dp[n] = 1;	dp[ n + 1 ] = 0;
		coltwo[j] = calcColumnTwo( j - 1, 0 );
		if ( colone[ j - 1 ] && colone[j] ){
			coltwo[j] --;
			if ( coltwo[j] < 0 )
				coltwo[j] += modulo;
		}
	}
	memset ( dp, -1, sizeof ( dp ) );
	dp[m] = 1;	dp[ m + 1 ] = 0;
	cout << calc( 0 ) << endl;
//	for ( i = 0; i < m; i ++ )	cout << colone[i] << " ";	cout << endl;
//	for ( i = 0; i < m; i ++ )	cout << coltwo[i] << " ";	cout << endl;
//	cin >> i;
	return 0;
}


#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

#define clr(x) memset((x), 0, sizeof(x))
#define pb push_back
#define mp make_pair
#define sz size()
#define For(i, st, en) for(int i=(st); i<=(int)(en); i++)
#define Ford(i, st, en) for(int i=(st); i>=(int)(en); i--)
#define forn(i, n) for(int i=0; i<(int)(n); i++)
#define ford(i, n) for(int i=(n)-1; i>=0; i--)
#define fori(it, x) for (__typeof((x).begin()) it = (x).begin(); it != (x).end(); it++)

template <class _T> inline _T sqr(const _T& x) { return x * x; }
template <class _T> inline string tostr(const _T& a) { ostringstream os(""); os << a; return os.str(); }

typedef long double ld;

// Constants
const ld PI = 3.1415926535897932384626433832795;
const ld EPS = 1e-11;

// Types
typedef long long i64;
typedef set < int > SI;
typedef vector < int > VI;
typedef map < string, int > MSI;
typedef pair < int, int > PII;

const int MOD = 1000000007;

inline void add(int &a, int b)
{
	a += b;
	if (a >= MOD) a -= MOD;
}

int n, m;
char s[1024][1024];
bool h[256][256];
bool v[256][256];
bool c[256];
int dc[256][256];
int d[256];

int main()
{
#ifdef ROOM_311
	freopen("input.txt", "rt", stdin);
	time_t et_0 = clock();
#else
#endif
	cout << setiosflags(ios::fixed) << setprecision(10);

	clr(h);
	clr(v);
	scanf("%d%d", &n, &m);
	forn(i, n * 4 + 1)
	{
		scanf("%s", s[i]);
	}
	forn(i, n)
	{
		forn(j, m)
		{
			int cnt = 0;
			forn(i1, 3)
			{
				forn(j1, 3)
				{
					cnt += s[i * 4 + i1 + 1][j * 4 + j1 + 1] == 'O';
				}
			}
			if (cnt == 0 || cnt == 1 || cnt == 4 || cnt == 5) h[i][j] = v[i][j] = true;
			else if (cnt == 2 || cnt == 3)
			{
				if (s[i * 4 + 1][j * 4 + 1] == 'O') h[i][j] = true;
				else v[i][j] = true;
			}
			else // if (cnt == 6)
			{
				if (s[i * 4 + 2][j * 4 + 1] == 'O') v[i][j] = true;
				else h[i][j] = true;
			}
//			cerr << h[i][j];
		}
//		cerr << endl;
	}
	forn(j, m)
	{
		c[j] = (n % 2 == 0);
		forn(i, n)
		{
			c[j] = c[j] && v[i][j];
		}
//		cerr << c[j] << endl;
	}

	clr(dc);
	clr(d);
	forn(j, m - 1)
	{
		dc[j][0] = 1;
		forn(i, n)
		{
			if (h[i][j] && h[i][j+1]) add(dc[j][i+1], dc[j][i]);
			if (i < n-1 && v[i][j] && v[i][j+1] && v[i+1][j] && v[i+1][j+1]) add(dc[j][i+2], dc[j][i]);
//			cerr << dc[j][i] << " ";
		}
		if (c[j] && c[j+1]) add(dc[j][n], MOD-1);
//		cerr << dc[j][n] << endl;
	}
//	cerr << endl;
	d[0] = 1;
	forn(j, m)
	{
		if (c[j]) add(d[j+1], d[j]);
		if (j < m-1) add(d[j+2], (i64)d[j] * dc[j][n] % MOD);
	}

	cout << d[m] << endl;

#ifdef ROOM_311
	time_t et_1 = clock();
	fprintf(stderr, "execution time = %0.0lf ms\n", (et_1 - et_0) * 1000.0 / CLOCKS_PER_SEC);
#endif
	return 0;
}


#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

#define clr(x) memset((x), 0, sizeof(x))
#define pb push_back
#define mp make_pair
#define sz size()
#define For(i, st, en) for(int i=(st); i<=(int)(en); i++)
#define Ford(i, st, en) for(int i=(st); i>=(int)(en); i--)
#define forn(i, n) for(int i=0; i<(int)(n); i++)
#define ford(i, n) for(int i=(n)-1; i>=0; i--)
#define fori(it, x) for (__typeof((x).begin()) it = (x).begin(); it != (x).end(); it++)

template <class _T> inline _T sqr(const _T& x) { return x * x; }
template <class _T> inline string tostr(const _T& a) { ostringstream os(""); os << a; return os.str(); }

typedef long double ld;

// Constants
const ld PI = 3.1415926535897932384626433832795;
const ld EPS = 1e-11;

// Types
typedef long long i64;
typedef set < int > SI;
typedef vector < int > VI;
typedef map < string, int > MSI;
typedef pair < int, int > PII;

const int MOD = 1000000007;

inline void add(int &a, int b)
{
	a += b;
	if (a >= MOD) a -= MOD;
}

int n, m;
char s[1024][1024];
bool h[256][256];
bool v[256][256];
bool c[256];
int dc[256][256];
int d[256];

int main()
{
#ifdef ROOM_311
	freopen("input.txt", "rt", stdin);
	time_t et_0 = clock();
#else
#endif
	cout << setiosflags(ios::fixed) << setprecision(10);

	clr(h);
	clr(v);
	scanf("%d%d", &n, &m);
	forn(i, n * 4 + 1)
	{
		scanf("%s", s[i]);
	}
	forn(i, n)
	{
		forn(j, m)
		{
			int cnt = 0;
			forn(i1, 3)
			{
				forn(j1, 3)
				{
					cnt += s[i * 4 + i1 + 1][j * 4 + j1 + 1] == 'O';
				}
			}
			if (cnt == 0 || cnt == 1 || cnt == 4 || cnt == 5) h[i][j] = v[i][j] = true;
			else if (cnt == 2 || cnt == 3)
			{
				if (s[i * 4 + 1][j * 4 + 1] == 'O') h[i][j] = true;
				else v[i][j] = true;
			}
			else // if (cnt == 6)
			{
				if (s[i * 4 + 2][j * 4 + 1] == 'O') v[i][j] = true;
				else h[i][j] = true;
			}
//			cerr << v[i][j];
		}
//		cerr << endl;
	}
	forn(j, m)
	{
		c[j] = (n % 2 == 0);
		forn(i, n)
		{
			c[j] = c[j] && v[i];
		}
//		cerr << c[j] << endl;
	}

	clr(dc);
	clr(d);
	forn(j, m - 1)
	{
		dc[j][0] = 1;
		forn(i, n)
		{
			if (h[i][j] && h[i][j+1]) add(dc[j][i+1], dc[j][i]);
			if (i > 0 && v[i][j] && v[i][j+1] && v[i-1][j] && v[i-1][j+1]) add(dc[j][i+1], dc[j][i-1]);
//			cerr << dc[j][i] << " ";
		}
		if (c[j] && c[j+1]) add(dc[j][n], MOD-1);
//		cerr << dc[j][n] << endl;
	}
//	cerr << endl;
	d[0] = 1;
	forn(j, m)
	{
		if (c[j]) add(d[j+1], d[j]);
		if (j < m-1) add(d[j+2], (i64)d[j] * dc[j][n] % MOD);
	}

	cout << d[m] << endl;

#ifdef ROOM_311
	time_t et_1 = clock();
	fprintf(stderr, "execution time = %0.0lf ms\n", (et_1 - et_0) * 1000.0 / CLOCKS_PER_SEC);
#endif
	return 0;
}


#include <stdio.h>

typedef long long LL;

#define MOD  1000000007
#define MAXN 300

char    s[5][MAXN*5];
bool    h[MAXN][MAXN];
bool    v[MAXN][MAXN];
bool    has[MAXN];
int     c[MAXN];
int     a[MAXN];
int     y, x;

bool is_vertical(int c)
{
    if (y % 2 == 1) return false;
    for(int i=1; i<=y; ++i) if (!v[i][c]) return false;
    return true;
}

LL solve()
{
    c[0] = 1;
    c[1] = is_vertical(1) ? 1 : 0;
    for(int i=2; i<=x; ++i)
    {
        c[i] = is_vertical(i) ? c[i-1] : 0;

        a[0] = 1;
        has[0] = true;
        a[1] = h[1][i-1] && h[1][i];
        has[1] = a[1] > 0;
        //printf("r[%i] = %i  has=%c\n", 1, a[1], has[1]?'+':'-');
        for(int j=2; j<=y; ++j)
        {
            has[j] = false;
            a[j] = 0;
            if (h[j][i-1] && h[j][i] && has[j-1])
            {
                has[j] = true;
                a[j] = a[j-1];
                //printf("h\n");
            }
            if (v[j][i-1] && v[j][i] && v[j-1][i-1] && v[j-1][i] && has[j-2])
            {
                has[j] = true;
                a[j] = (a[j] + a[j-2]) % MOD;
                //printf("v\n");
            }
            //printf("r[%i] = %i  has=%c\n", j, a[j], has[j]?'+':'-');
        }
        if (has[y])
        {
            if (is_vertical(i) && is_vertical(i - 1)) a[y] = (a[y] + MOD - 1) % MOD;
            c[i] = (c[i] + (LL)a[y]*c[i - 2]) % MOD;
        }
        //printf("c %i = %i\n", i, c[i]);
    }
    return c[x];
}

int q(char c)
{
    return c=='O'?1:0;
}

int main()
{
    freopen("d.in", "r", stdin);
    gets(s[0]);
    sscanf(s[0], "%i %i", &y, &x);
    for(int i=0; i<y; ++i)
    {
        for(int j=0; j<4; ++j) gets(s[j]);
        //for(int j=0; j<4; ++j) printf("%i: %s\n", j, s[j]);
        for(int j=0; j<x; ++j)
        {
            int k = j*4;
            int V = q(s[2][k + 1]) + q(s[3][k+1]);
            int H = q(s[1][k+1]) + q(s[1][k+2]);
            //printf("%i %i  V=%i H=%i\n", i, j, V, H);
            if (V > H) v[i+1][j+1] = true;
            else if (V < H) h[i+1][j+1] = true;
            else v[i+1][j+1] = h[i+1][j+1] = true;
        }
    }
    /*
    for(int i=1; i<=y; ++i)
    {
        for(int j=1; j<=x; ++j) if (h[i][j] && v[i][j]) printf("+"); else if (h[i][j]) printf("-"); else printf("|");
        printf("\n");
    }
    */
    printf("%I64d\n", solve());
}


#include <stdio.h>

typedef long long LL;

#define MOD  1000000007
#define MAXN 300

char    s[5][MAXN*5];
bool    h[MAXN][MAXN];
bool    v[MAXN][MAXN];
bool    has[MAXN];
int     c[MAXN];
int     a[MAXN];
int     y, x;

bool is_vertical(int c)
{
    if (y % 2 == 1) return false;
    for(int i=1; i<=y; ++i) if (!v[i][c]) return false;
    return true;
}

LL solve()
{
    c[0] = 1;
    c[1] = is_vertical(1) ? 1 : 0;
    for(int i=2; i<=x; ++i)
    {
        c[i] = is_vertical(i) ? c[i-1] : 0;

        a[0] = 1;
        has[0] = true;
        a[1] = h[1][i-1] && h[1][i];
        has[1] = a[1] > 0;
        //printf("r[%i] = %i  has=%c\n", 1, a[1], has[1]?'+':'-');
        for(int j=2; j<=y; ++j)
        {
            has[j] = false;
            a[j] = 0;
            if (h[j][i-1] && h[j][i] && has[j-1])
            {
                has[j] = true;
                a[j] = a[j-1];
                //printf("h\n");
            }
            if (v[j][i-1] && v[j][i] && v[j-1][i-1] && v[j-1][i] && has[j-2])
            {
                has[j] = true;
                a[j] = (a[j] + a[j-2]) % MOD;
                //printf("v\n");
            }
            //printf("r[%i] = %i  has=%c\n", j, a[j], has[j]?'+':'-');
        }
        if (has[y])
        {
            if (is_vertical(i) && is_vertical(i - 1)) a[y] = (a[y] + MOD - 1) % MOD;
            c[i] = (c[i] + (LL)a[y]*c[i - 2]) % MOD;
        }
        //printf("c %i = %i\n", i, c[i]);
    }
    return c[x];
}

int q(char c)
{
    return c=='O'?1:0;
}

int main()
{
    //freopen("d.in", "r", stdin);
    gets(s[0]);
    sscanf(s[0], "%i %i", &y, &x);
    for(int i=0; i<y; ++i)
    {
        for(int j=0; j<4; ++j) gets(s[j]);
        //for(int j=0; j<4; ++j) printf("%i: %s\n", j, s[j]);
        for(int j=0; j<x; ++j)
        {
            int k = j*4;
            int V = q(s[2][k + 1]) + q(s[3][k+1]);
            int H = q(s[1][k+1]) + q(s[1][k+2]);
            //printf("%i %i  V=%i H=%i\n", i, j, V, H);
            if (V > H) v[i+1][j+1] = true;
            else if (V < H) h[i+1][j+1] = true;
            else v[i+1][j+1] = h[i+1][j+1] = true;
        }
    }
    /*
    for(int i=1; i<=y; ++i)
    {
        for(int j=1; j<=x; ++j) if (h[i][j] && v[i][j]) printf("+"); else if (h[i][j]) printf("-"); else printf("|");
        printf("\n");
    }
    */
    printf("%I64d\n", solve());
}


#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define MAXN 310
#define MAXM 1210
#define MO 1000000007

typedef long long LL;

const int hor[] = {0, 16, 257, 273, 325, 341, 455};
const int ver[] = {0, 16, 68, 84, 325, 341, 365};

char mp[MAXM][MAXM];
int g[MAXN][MAXN];
int f[MAXN];
int n, m;

void init()
{
  scanf("%d%d", &n, &m);
  for (int i = 0; i < 4*n+1; ++i) scanf("%s", mp[i]);
}

int val_pd(int x, int y)
{
  int cur = 0;
  for (int i = 2; i >= 0; --i)
    for (int j = 2; j >= 0; --j) cur = cur*2 + (mp[x+i][y+j] == 'O');

  int val = 0;
  for (int i = 0; i < 7; ++i) {
    if (hor[i] == cur) val |= 1;
    if (ver[i] == cur) val |= 2;
  }
  return val;
}

void g_cal()
{
  for (int i = 1; i < 4*n+1; i += 4)
    for (int j = 1; j < 4*m+1; j += 4)
      g[i/4][j/4] = val_pd(i, j);
}

int vec_cal(int col)
{
  if (n%2) return 0;
  for (int i = 0; i < n; ++i)
    if ((g[i][col] & 2) == 0) return 0;
  return 1;
}

int hor_cal(int col)
{
  int f[MAXN];
  f[0] = 1;
  f[1] = ((g[0][col] & 1) && (g[0][col-1] & 1));
  for (int i = 2; i <= n; ++i) {
    f[i] = 0;
    if ((g[i-1][col] & 1) && (g[i-1][col-1] & 1)) f[i] = f[i-1];
    if ((g[i-1][col] & 2) && (g[i-1][col-1] & 2) && (g[i-2][col] & 2) && (g[i-2][col-1] & 2)) f[i] = ((LL)f[i]+f[i-2])%MO;
  }

  return f[n] - (vec_cal(col) && vec_cal(col-1));
}

void solve()
{
  g_cal();
  // for (int i = 0; i < n; ++i) {
  //   for (int j = 0; j < m; ++j) printf("%d ", g[i][j]);
  //   puts("");
  // }

  f[0] = 1;
  f[1] = vec_cal(0);
  for (int i = 2; i <= m; ++i)
    f[i] = ((LL)f[i-1]*vec_cal(i-1) + (LL)f[i-2]*hor_cal(i-1))%MO;

  printf("%d\n", f[m]);
}

int main()
{
  init();
  solve();
  return 0;
}


#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define MAXN 310
#define MAXM 1210
#define MO 1000000007

typedef long long LL;

const int hor[] = {0, 16, 257, 273, 325, 341, 455};
const int ver[] = {0, 16, 68, 84, 325, 341, 365};

char mp[MAXM][MAXM];
int g[MAXN][MAXN];
int f[MAXN];
int n, m;

void init()
{
  scanf("%d%d", &n, &m);
  for (int i = 0; i < 4*n+1; ++i) scanf("%s", mp[i]);
}

int val_pd(int x, int y)
{
  int cur = 0;
  for (int i = 2; i >= 0; --i)
    for (int j = 2; j >= 0; --j) cur = cur*2 + (mp[x+i][y+j] == 'O');

  int val = 0;
  for (int i = 0; i < 7; ++i) {
    if (hor[i] == cur) val |= 1;
    if (ver[i] == cur) val |= 2;
  }
  return val;
}

void g_cal()
{
  for (int i = 1; i < 4*n+1; i += 4)
    for (int j = 1; j < 4*m+1; j += 4)
      g[i/4][j/4] = val_pd(i, j);
}

int vec_cal(int col)
{
  if (n%2) return 0;
  for (int i = 0; i < n; ++i)
    if ((g[i][col] & 2) == 0) return 0;
  return 1;
}

int hor_cal(int col)
{
  int f[MAXN];
  f[0] = 1;
  f[1] = ((g[0][col] & 1) && (g[0][col-1] & 1));
  for (int i = 2; i <= n; ++i) {
    f[i] = 0;
    if ((g[i-1][col] & 1) && (g[i-1][col-1] & 1)) f[i] = f[i-1];
    if ((g[i-1][col] & 2) && (g[i-1][col-1] & 2) && (g[i-2][col] & 2) && (g[i-2][col-1] & 2)) f[i] = ((LL)f[i]+f[i-2])%MO;
  }

  return f[n] - (vec_cal(col) && vec_cal(col));
}

void solve()
{
  g_cal();
  // for (int i = 0; i < n; ++i) {
  //   for (int j = 0; j < m; ++j) printf("%d ", g[i][j]);
  //   puts("");
  // }

  f[0] = 1;
  f[1] = vec_cal(0);
  for (int i = 2; i <= m; ++i)
    f[i] = ((LL)f[i-1]*vec_cal(i-1) + (LL)f[i-2]*hor_cal(i-1))%MO;

  printf("%d\n", f[m]);
}

int main()
{
  init();
  solve();
  return 0;
}


#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define MAXN 310
#define MAXM 1210
#define MO 1000000007

typedef long long LL;

const int hor[] = {0, 16, 257, 273, 325, 341, 455};
const int ver[] = {0, 16, 68, 84, 325, 341, 365};

char mp[MAXM][MAXM];
int g[MAXN][MAXN];
int f[MAXN];
int n, m;

void init()
{
  scanf("%d%d", &n, &m);
  for (int i = 0; i < 4*n+1; ++i) scanf("%s", mp[i]);
}

int val_pd(int x, int y)
{
  int cur = 0;
  for (int i = 2; i >= 0; --i)
    for (int j = 2; j >= 0; --j) cur = cur*2 + (mp[x+i][y+j] == 'O');

  int val = 0;
  for (int i = 0; i < 7; ++i) {
    if (hor[i] == cur) val |= 1;
    if (ver[i] == cur) val |= 2;
  }
  return val;
}

void g_cal()
{
  for (int i = 1; i < 4*n+1; i += 4)
    for (int j = 1; j < 4*m+1; j += 4)
      g[i/4][j/4] = val_pd(i, j);
}

int vec_cal(int col)
{
  if (n%2) return 0;
  for (int i = 0; i < n; ++i)
    if ((g[i][col] & 2) == 0) return 0;
  return 1;
}

int hor_cal(int col)
{
  int f[MAXN];
  f[0] = 1;
  f[1] = ((g[0][col] & 1) && (g[0][col-1] & 1));
  for (int i = 2; i <= n; ++i) {
    f[i] = 0;
    if ((g[i-1][col] & 1) && (g[i-1][col-1] & 1)) f[i] = f[i-1];
    if ((g[i-1][col] & 2) && (g[i-1][col-1] & 2) && (g[i-2][col] & 2) && (g[i-2][col-1] & 2)) f[i] = ((LL)f[i]+f[i-2])%MO;
  }

  return f[n] - (vec_cal(col) && vec_cal(col-1));
}

void solve()
{
  g_cal();
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) printf("%d ", g[i][j]);
    puts("");
  }

  f[0] = 1;
  f[1] = vec_cal(0);
  for (int i = 2; i <= m; ++i)
    f[i] = ((LL)f[i-1]*vec_cal(i-1) + (LL)f[i-2]*hor_cal(i-1))%MO;

  printf("%d\n", f[m]);
}

int main()
{
  init();
  solve();
  return 0;
}


#include<stdio.h>
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#include<memory.h>
#include<map>
#include<set>
#include<queue>
#include<list>
#include<sstream>
#define mp make_pair
#define pb push_back
#define F first
#define S second
#define SS stringstream
#define sqr(x) ((x)*(x))
#define m0(x) memset(x,0,sizeof(x))
#define m1(x) memset(x,63,sizeof(x))
#define CC(x) cout << (x) << endl
#define SV(x) sort(x.begin(),x.end())
#define pw(x) (1ull<<(x))
using namespace std;
typedef pair<int,int> pt;
typedef vector<int> vt;
typedef unsigned long long UL;
#define M 1000000007

int n,m,nn,q[333][333];
char a[1111][1111];
long long q1[333],q2[333],d[333];

int main(){
//	freopen("1.in","r",stdin);
//	freopen("1.out","w",stdout);
	scanf("%d%d\n",&n,&m);
	nn=n*4+1;
	for (int i=0;i<nn;i++)gets(a[i]);
	for (int i=0;i<n;i++)for (int j=0;j<m;j++){
		string s="";
		for (int ii=0;ii<3;ii++)for (int jj=0;jj<3;jj++)s+=a[i*4+1+ii][j*4+1+jj];
		if (s==".........")q[i][j]=3;
		if (s=="....O....")q[i][j]=3;
		if (s=="..O...O..")q[i][j]=1;
		if (s=="O.......O")q[i][j]=2;
		if (s=="..O.O.O..")q[i][j]=1;
		if (s=="O...O...O")q[i][j]=2;
		if (s=="O.O...O.O")q[i][j]=3;
		if (s=="O.O.O.O.O")q[i][j]=3;
		if (s=="O.OO.OO.O")q[i][j]=1;
		if (s=="OOO...OOO")q[i][j]=2;
	}
	for (int i=0;i<m;i++){
		if (n%2==0){
			int t=0;
			for (int j=0;j<n;j++)if (q[j][i]==2)t=1;
			if (!t)q1[i]=1;
		}
		if (i<m-1){
			m0(d);
			d[0]=1;
			for (int j=0;j<n;j++){
				if (q[j][i]!=1&&q[j][i+1]!=1)d[j+1]=(d[j+1]+d[j])%M;
				if (j<n-1&&q[j][i]!=2&&q[j][i+1]!=2&&q[j+1][i]!=2&&q[j+1][i+1]!=2)d[j+2]=(d[j+2]+d[j])%M;
			}
			q2[i]=d[n];
		}
	}
	for (int i=0;i<m-1;i++)if (q1[i]&&q1[i+1])q2[i]=(q2[i]-1+M)%M;
	m0(d);
	d[0]=1;
	for (int i=0;i<m;i++){
		d[i+1]=(d[i+1]+d[i]*q1[i])%M;
		d[i+2]=(d[i+2]+d[i]*q2[i])%M;
	}
	CC(d[m]);
	return 0;
}


#include<stdio.h>
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#include<memory.h>
#include<map>
#include<set>
#include<queue>
#include<list>
#include<sstream>
#define mp make_pair
#define pb push_back
#define F first
#define S second
#define SS stringstream
#define sqr(x) ((x)*(x))
#define m0(x) memset(x,0,sizeof(x))
#define m1(x) memset(x,63,sizeof(x))
#define CC(x) cout << (x) << endl
#define SV(x) sort(x.begin(),x.end())
#define pw(x) (1ull<<(x))
using namespace std;
typedef pair<int,int> pt;
typedef vector<int> vt;
typedef unsigned long long UL;
#define M 1000000007

int n,m,nn,q[333][333];
char a[1111][1111];
long long q1[333],q2[333],d[333];

int main(){
//	freopen("1.in","r",stdin);
//	freopen("1.out","w",stdout);
	scanf("%d%d\n",&n,&m);
	nn=n*4+1;
	for (int i=0;i<nn;i++)gets(a[i]);
	for (int i=0;i<n;i++)for (int j=0;j<m;j++){
		string s="";
		for (int ii=0;ii<3;ii++)for (int jj=0;jj<3;jj++)s+=a[i*4+1+ii][j*4+1+jj];
		if (s==".........")q[i][j]=3;
		if (s=="....O....")q[i][j]=3;
		if (s=="..O...O..")q[i][j]=1;
		if (s=="O.......O")q[i][j]=2;
		if (s=="..O.O.O..")q[i][j]=1;
		if (s=="O...O...O")q[i][j]=2;
		if (s=="O.O...O.O")q[i][j]=3;
		if (s=="O.O.O.O.O")q[i][j]=3;
		if (s=="O.OO.OO.O")q[i][j]=1;
		if (s=="OOO...OOO")q[i][j]=2;
	}
	for (int i=0;i<m;i++){
		if (n%2==0){
			int t=0;
			for (int j=0;j<n;j++)if (q[i][j]==2)t=1;
			if (!t)q1[i]=1;
		}
		if (i<m-1){
			m0(d);
			d[0]=1;
			for (int j=0;j<n;j++){
				if (q[j][i]!=1&&q[j][i+1]!=1)d[j+1]=(d[j+1]+d[j])%M;
				if (j<n-1&&q[j][i]!=2&&q[j][i+1]!=2&&q[j+1][i]!=2&&q[j+1][i+1]!=2)d[j+2]=(d[j+2]+d[j])%M;
			}
			q2[i]=d[n];
		}
	}
	for (int i=0;i<m-1;i++)if (q1[i]&&q1[i+1])q2[i]=(q2[i]-1+M)%M;
	m0(d);
	d[0]=1;
	for (int i=0;i<m;i++){
		d[i+1]=(d[i+1]+d[i]*q1[i])%M;
		d[i+2]=(d[i+2]+d[i]*q2[i])%M;
	}
	CC(d[m]);
	return 0;
}


#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=256;
const int Mod=1e9+7;
const string horizontal_shape[7]=
{
    ".........",
    "....O....",
    "O.......O",
    "O...O...O",
    "O.O...O.O",
    "O.O.O.O.O",
    "OOO...OOO"
};
const string vertical_shape[7]=
{
    ".........",
    "....O....",
    "..O...O..",
    "..O.O.O..",
    "O.O...O.O",
    "O.O.O.O.O",
    "O.OO.OO.O"
};

int m,n;
pair <int,int> Shape[N][N];
string Str[N][N];
int F[N];
int G[N][2];

char Get(){
    char ch=getchar();
    while (ch!='O' && ch!='.') ch=getchar();
    return ch;
}

pair <int,int> Get_Shape(string &S){
    int ret_ver=-1;
    int ret_hor=-1;
    for (int i=0;i<7;i++){
        if (S==horizontal_shape[i]) ret_hor=i;
        if (S==vertical_shape[i]) ret_ver=i;
    }
    pair <int,int> ret;
    if (ret_ver!=-1 && ret_hor!=-1){
        ret.first=ret_ver;
        ret.second=3;
    }else
    if (ret_ver!=-1){
        ret.first=ret_ver;
        ret.second=1;
    }
    else{
        ret.first=ret_hor;
        ret.second=2;
    }
    return ret;
}

void read_data(){
    scanf("%d%d",&m,&n);
    for (int i=1;i<=m;i++)
      for (int j=1;j<=n;j++)
        Str[i][j]="";
    for (int i=1;i<=m;i++){
        for (int k=0;k<3;k++)
          for (int j=1;j<=n;j++){
             Str[i][j]+=Get();
             Str[i][j]+=Get();
             Str[i][j]+=Get();
          }
    }
    for (int i=1;i<=m;i++)
      for (int j=1;j<=n;j++)
        Shape[i][j]=Get_Shape(Str[i][j]);
}

void dp(){
    F[0]=1;
    for (int j=0;j<n;j++){
        // No Horizontal
        if (m%2==0){
            bool check=true;
            for (int i=1;i<=m;i++)
              if (Shape[i][j+1].second==2){
                check=false;
                break;
              }
            if (check) { F[j+1]+=F[j]; F[j+1]%=Mod; }
        }
        if (j==n-1) continue;
        // with Horizontal
        G[0][0]=1;
        G[0][1]=0;
        for (int i=1;i<=m;i++) G[i][0]=G[i][1]=0;
        for (int i=0;i<m;i++){
            if (Shape[i+1][j+1].second!=1 && Shape[i+1][j+2].second!=1){
                G[i+1][1]+=G[i][0]; G[i+1][1]%=Mod;
                G[i+1][1]+=G[i][1]; G[i+1][1]%=Mod;
            }
            if (i==m-1) continue;
            if (Shape[i+1][j+1].second!=2 && Shape[i+1][j+2].second!=2
            &&  Shape[i+2][j+1].second!=2 && Shape[i+2][j+2].second!=2){
                G[i+2][0]+=G[i][0]; G[i+2][0]%=Mod;
                G[i+2][1]+=G[i][1]; G[i+2][1]%=Mod;
            }
        }
        F[j+2]=( F[j+2]+((long long)(F[j])*G[m][1])%Mod ) % Mod;
    }
    cout << F[n] << endl;
}

int main(){
    read_data();
    dp();
    return 0;
}


#include <iostream>
#include <cstdio>
#include <queue>

using namespace std;

int n, m;
char s[1000][1001];

const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, -1, 0, 1};

int main(){
	scanf("%d%d\n", &n, &m);
	for (int i = 0; i < n; i++)
		gets(s[i]);
	pair<int, int> beg(-1, -1);
	for (int i = 0; beg.first == -1; i++)
		for (int j = 0; beg.first == -1 && j < m; j++)
			if (s[i][j] == 'E')
				beg = make_pair(i, j);
	queue<pair<int, int> > que;
	que.push(beg);
	int ans = 0;
	bool found = false;
	while (!found){
		int &x = que.front().first, &y = que.front().second;
		s[x][y] = 'T';
		for (int i = 0; i < 4; i++)
			if (x + dx[i] >= 0 && x + dx[i] < n && y + dy[i] >= 0 && y + dy[i] < m && s[x + dx[i]][y + dy[i]] != 'T'){
				que.push(make_pair(x + dx[i], y + dy[i]));
				if (s[x + dx[i]][y + dy[i]] == 'S')
					found = true;
				else
					ans += s[x + dx[i]][y + dy[i]] - '0';
				s[x + dx[i]][y + dy[i]] = 'T';
			}
		que.pop();
	}
	printf("%d\n", ans);
	return 0;
}


#include <iostream>
#include <cstdio>
#include <queue>

using namespace std;

int n, m;
char s[1000][1001];

const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, -1, 0, 1};

int main(){
	scanf("%d%d\n", &n, &m);
	for (int i = 0; i < n; i++)
		gets(s[i]);
	pair<int, int> beg(-1, -1);
	for (int i = 0; beg.first == -1; i++)
		for (int j = 0; beg.first == -1 && j < m; j++)
			if (s[i][j] == 'E')
				beg = make_pair(i, j);
	queue<pair<int, int> > que;
	que.push(beg);
	int ans = 0;
	bool found = false;
	while (!found){
		int &x = que.front().first, &y = que.front().second;
		for (int i = 0; i < 4; i++)
			if (x + dx[i] >= 0 && x + dx[i] < n && y + dy[i] >= 0 && y + dy[i] < m && s[x + dx[i]][y + dy[i]] != 'T'){
				que.push(make_pair(x + dx[i], y + dy[i]));
				if (s[x + dx[i]][y + dy[i]] == 'S')
					found = true;
				if (s[x + dx[i]][y + dy[i]] >= '0' && s[x + dx[i]][y + dy[i]] <= '9')
					ans += s[x + dx[i]][y + dy[i]] - '0';
			}
		s[x][y] = 'T';
		que.pop();
	}
	printf("%d\n", ans);
	return 0;
}


#include <iostream>
#include <cstdio>
#include <queue>

using namespace std;

int n, m;
char s[1000][1001];

const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, -1, 0, 1};

int main(){
	scanf("%d%d\n", &n, &m);
	for (int i = 0; i < n; i++)
		gets(s[i]);
	pair<int, int> beg(-1, -1);
	for (int i = 0; beg.first == -1; i++)
		for (int j = 0; beg.first == -1 && j < m; j++)
			if (s[i][j] == 'E')
				beg = make_pair(i, j);
	queue<pair<int, int> > que;
	que.push(beg);
	int ans = 0;
	bool found = false;
	while (!found){
		int &x = que.front().first, &y = que.front().second;
		s[x][y] = 'T';
		for (int i = 0; i < 4; i++)
			if (x + dx[i] >= 0 && x + dx[i] < n && y + dy[i] >= 0 && y + dy[i] < m && s[x + dx[i]][y + dy[i]] != 'T'){
				que.push(make_pair(x + dx[i], y + dy[i]));
				if (s[x + dx[i]][y + dy[i]] == 'S')
					found = true;
				if (s[x + dx[i]][y + dy[i]] >= '0' && s[x + dx[i]][y + dy[i]] <= '9')
					ans += s[x + dx[i]][y + dy[i]] - '0';
				s[x + dx[i]][y + dy[i]] = 'T';
			}
		que.pop();
	}
	printf("%d\n", ans);
	return 0;
}


#include <iostream>
#include <cstdio>
#include <queue>

using namespace std;

int n, m;
char s[1000][1001];

const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, -1, 0, 1};

int main(){
	scanf("%d%d\n", &n, &m);
	for (int i = 0; i < n; i++)
		gets(s[i]);
	pair<int, int> beg(-1, -1);
	for (int i = 0; beg.first == -1; i++)
		for (int j = 0; beg.first == -1 && j < m; j++)
			if (s[i][j] == 'E')
				beg = make_pair(i, j);
	queue<pair<int, int> > que;
	que.push(beg);
	int ans = 0;
	bool found = false;
	while (!found){
		int qsize = que.size();
		for (int qwe = 0; qwe < qsize; qwe++){
			int &x = que.front().first, &y = que.front().second;
			s[x][y] = 'T';
			for (int i = 0; i < 4; i++)
				if (x + dx[i] >= 0 && x + dx[i] < n && y + dy[i] >= 0 && y + dy[i] < m && s[x + dx[i]][y + dy[i]] != 'T'){
					que.push(make_pair(x + dx[i], y + dy[i]));
					if (s[x + dx[i]][y + dy[i]] == 'S')
						found = true;
					else
						ans += s[x + dx[i]][y + dy[i]] - '0';
					s[x + dx[i]][y + dy[i]] = 'T';
				}
			que.pop();
		}
	}
	printf("%d\n", ans);
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <utility>
#include <functional>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <ctime>
#include <cmath>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pdd paur<double, double>
#define fi first
#define se second
#define forn(i,a,b) for( int i = (a); i < (b); i++ )
#define rep(i,n) for( int i = 0; i < (n); i++ )
#define forever for(;;)

const int MXN = 1010;
const int INF = (int)1e9;
const ll LINF = (ll)1e18;

const int mod = 1000000007;

char mpp [MXN][MXN];
pii q [MXN*MXN];
int d [MXN][MXN];

int di [] = {0,0,1,-1};
int dj [] = {1,-1,0,0};

int n,m;
void bfs( int ii, int jj ){
    int ql = 0, qr = 0;
    rep(i,n)
        rep(j,m)
            d[i][j] = INF;
    d[ii][jj] = 0;
    q[qr++] = mp(ii,jj);
    while(ql<qr){
        pii cur = q[ql++];
        rep(k,4){
            int ni = cur.fi + di[k];
            int nj = cur.se + dj[k];
            if( ni>=0 && nj>=0 && ni<n && nj<m && mpp[ni][nj]!='T' && d[ni][nj]==INF ){
                d[ni][nj] = d[cur.fi][cur.se] + 1;
                q[qr++] = mp(ni,nj);
            }
        }
    }
}

int main(){
    scanf("%d%d", &n, &m);

    int ie,je,is,js;
    rep(i,n){
        scanf("%s", mpp[i]);
        rep(j,m)
            if(mpp[i][j]=='E') ie = i, je = j;
            else if(mpp[i][j]=='S') is = i, js = j;
    }

    bfs(ie,je);

    int res = 0;
    rep(i,n){
        rep(j,m)
            if('0'<=mpp[i][j] && mpp[i][j]<='9' && d[i][j]<=d[is][js]) res += mpp[i][j]-'0';
    }

    printf("%d", res);
}


#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<algorithm>
#include<queue>
using namespace std;

#define maxm 1050

struct node{
    int cost,x,y;
    node(){}
    node(int _x,int _y,int _c){
        x=_x; y=_y; cost=_c;
    }
};

int dirx[]={1,-1,0,0};
int diry[]={0,0,1,-1};
int d[maxm][maxm];
queue<node>q;
int r,c;
char s[maxm][maxm];

void bfs(node s);

int main(){

    int i,j,k,l,test,t=1;

    //freopen("in.txt","r",stdin);

    scanf("%d %d",&r,&c);

    for(i=1;i<=r;i++){
        scanf("%s",s[i]+1);
    }

    node so;
    memset(d,-1,sizeof(d));
    for(i=1;i<=r;i++){
        for(j=1;j<=c;j++){
            if(s[i][j]=='E'){
                node s1=node(i,j,0);
                bfs(s1);
             }
             if(s[i][j]=='S'){
                 so=node(i,j,0);
             }
        }
    }

    int req=d[so.x][so.y];

    int ans=0;

    for(i=1;i<=r;i++){
        for(j=1;j<=c;j++){
            if(d[i][j]==-1)  continue;
            if(d[i][j]>req) continue;
            if(isdigit(s[i][j])){
                ans+=(s[i][j]-'0');
            }
        }
    }

    printf("%d\n",ans);

    return 0;
}

void bfs(node s1){

    int i,j,k,l;
    node temp,temp1;

    d[s1.x][s1.y]=0;

    q.push(s1);

    while(!q.empty()){

        temp=q.front(); q.pop();

        i=temp.x; j=temp.y;
        for(int i1=0;i1<4;i1++){
            k=i+dirx[i1]; l=j+diry[i1];
            if(k<1 || l<1 || k>r || l>c || s[k][l]=='T') continue;
            if(d[k][l]!=-1) continue;
            d[k][l]=temp.cost+1;
            temp1=node(k,l,d[k][l]);
            q.push(temp1);
        }
    }
}


#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <functional>
#include <numeric>
#include <bitset>

using namespace std;

typedef long long li;
typedef long double ld;

template <typename T>
T sqr(const T &x) {
    return x * x;
}

template <typename T>
T t_abs(const T &x) {
    return (x < 0) ? (-x) : x;
}

#define abs(x) t_abs(x)

const int N = 1050;
int n, m;
char a[N][N];
int d[N][N];

const int dx[] = {-1, 1, 0, 0};
const int dy[] = {0, 0, -1, 1};

const int INF = 1e9;

void bfs(int x, int y) {
    queue < pair <int, int> > q;
    q.push(make_pair(x, y));
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            d[i][j] = INF;
    d[x][y] = 0;
    while (!q.empty()) {
        x = q.front().first;
        y = q.front().second;
        q.pop();
        for (int dd = 0; dd < 4; dd++) {
            int nx = x + dx[dd];
            int ny = y + dy[dd];
            if (nx < 0 || nx >= n || ny < 0 || ny >= m)
                continue;
            if (a[nx][ny] == 'T')
                continue;
            if (d[nx][ny] == INF) {
                d[nx][ny] = d[x][y] + 1;
                q.push(make_pair(nx, ny));
            }
        }
    }
}

bool solve(int test) {
    if (scanf("%d%d", &n, &m) != 2)
        return false;
    for (int i = 0; i < n; i++)
        scanf("%s", a[i]);
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) {
            if (a[i][j] == 'S')
                bfs(i, j);
        }
    int dst;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) {
            if (a[i][j] == 'E') {
                dst = d[i][j];
                bfs(i, j);
            }
        }
    int ans = 0;
//    cerr << dst << endl;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
//            cerr << d[i][j] << ' ';
            if (d[i][j] <= dst && isdigit(a[i][j]))
                ans += a[i][j] - '0';

        }
//        cerr << endl;
    }
    printf("%d\n", ans);
    return true;
}

int main() {
#ifdef KUVIMAN
    freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
#endif
    int test = 0;
    while (solve(test))
        test++;
#ifdef KUVIMAN
    cerr << "== TIME: " << clock() << " ==" << endl;
#endif
    return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <string>
#define LL long long
#define DB double
#define SF scanf
#define PF printf
#define N 1009
#define bug cout<<"bug"<<endl;
using namespace std;
char ch[N];
int n,m;
struct nod{
    int x,y;
} st,en;
int re[N][N];
int dis[N][N];
queue<nod> que;
int dx[]={0,0,-1,1};
int dy[] = {-1,1,0,0};
int oor(int x,int y)
{
    if(x<0||x>=n) return false;
    if(y<0||y>=m) return false;
    return true;
}
void mindis()
{
    que.push(en);
    dis[en.x][en.y] = 1;
    nod e,t;
    while(!que.empty())
    {
        e = que.front();que.pop();
        for(int i=0;i<4;i++)
        {
            int tx= e.x+dx[i],ty=e.y+dy[i];
            if(!oor(tx,ty)||re[tx][ty]==-1||dis[tx][ty]) continue;
            dis[tx][ty] = dis[e.x][e.y]+1;
            t.x = tx;t.y = ty;
            que.push(t);
        }
    }
//    for(int i=0;i<n;i++)
//    {
//        for(int j=0;j<m;j++)
//        cout<<dis[i][j]<<" ";
//        cout<<endl;
//    }
}
int solve()
{
    int ret=0;
    int d = dis[st.x][st.y];
    for(int i=0;i<n;i++)
    for(int j=0;j<m;j++)
    if(dis[i][j]<=d&&re[i][j]>0)
    {
        ret+=re[i][j];
    }return ret;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    SF("%d%d",&n,&m);
    for(int i=0;i<n;i++)
    {
        SF("%s",ch);
        for(int j=0;j<m;j++)
        {
            if(ch[j]=='S')
            {
                st.x = i;
                st.y = j;
            }else if(ch[j]=='E')
            {
                en.x = i;
                en.y = j;
            }else if(ch[j]=='T')
            {
                re[i][j] = -1;
            }else
            {
                re[i][j] = ch[j] - '0';
            }
        }
    }
    mindis();
    PF("%d\n",solve());
    return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <string>
#define LL long long
#define DB double
#define SF scanf
#define PF printf
#define N 1009
#define bug cout<<"bug"<<endl;
using namespace std;
char ch[N];
int n,m;
struct nod{
    int x,y;
} st,en;
int re[N][N];
int dis[N][N];
int v[N][N];
queue<nod> que;
int dx[] = {0,0,-1,1};
int dy[] = {-1,1,0,0};
int oor(int x,int y)
{
    if(x<0||x>=n) return false;
    if(y<0||y>=m) return false;
    return true;
}
void mindis()
{
    que.push(en);
    dis[en.x][en.y] = 1;
    nod e,t;
    while(!que.empty())
    {
        e = que.front();que.pop();
        v[e.x][e.y] = 1;
        for(int i=0;i<4;i++)
        {
            int tx= e.x+dx[i],ty=e.y+dy[i];
            if(!oor(tx,ty)||re[tx][ty]==-1||dis[tx][ty]) continue;
            dis[tx][ty] = dis[e.x][e.y]+1;
            t.x = tx;t.y = ty;
            que.push(t);
        }
    }
//    for(int i=0;i<n;i++)
//    {
//        for(int j=0;j<m;j++)
//        cout<<dis[i][j]<<" ";
//        cout<<endl;
//    }
}
int solve()
{
    int ret=0;
    int d = dis[st.x][st.y];
    for(int i=0;i<n;i++)
    for(int j=0;j<m;j++)
    if(dis[i][j]<=d&&re[i][j]>0&&v[i][j])
    {
        ret+=re[i][j];
    }return ret;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    SF("%d%d",&n,&m);
    for(int i=0;i<n;i++)
    {
        SF("%s",ch);
        for(int j=0;j<m;j++)
        {
            if(ch[j]=='S')
            {
                st.x = i;
                st.y = j;
            }else if(ch[j]=='E')
            {
                en.x = i;
                en.y = j;
            }else if(ch[j]=='T')
            {
                re[i][j] = -1;
            }else
            {
                re[i][j] = ch[j] - '0';
            }
        }
    }
    mindis();
    PF("%d\n",solve());
    return 0;
}


#include <iostream>
#include <string>
#include <deque>

using namespace std;

int main()
{
	int r, c;
	cin >> r >> c;
	int **m, **dist;
	m = (int**)malloc(r*sizeof(int*));
	dist = (int**)malloc(r*sizeof(int*));
	for (int i = 0; i < r; i++)
	{
		m[i] = new int[c];
		dist[i] = new int[c];
	}
	const int INF = 1000000;
	for (int i = 0; i < r; i++)
		for (int j = 0; j < c; j++)
			dist[i][j] = INF;
	deque<int> q;
	for (int i = 0; i < r; i++)
	{
		string line;
		cin >> line;
		for (int j = 0; j < c; j++)
		{
			if (line[j] == 'T')
				m[i][j] = -1;
			else if (line[j] == 'S')
				m[i][j] = -2;
			else if (line[j] == 'E')
			{
				q.push_back(i*1000+j);
				dist[i][j] = 0;
				m[i][j] = -3;
			}
			else
				m[i][j] = line[j] - '0';
		}
	}
	bool isDone = false;
	int battle_count = 0, currDist = 0;
	while (!q.empty())
	{
		int i = q.front() / 1000, j = q.front() % 1000;
		q.pop_front();
		if (isDone && dist[i][j] > currDist)
			break;
		else if (dist[i][j] > currDist)
			currDist = dist[i][j];
		if (m[i][j] == -2)
			isDone = true;
		else if (m[i][j] > 0)
			battle_count += m[i][j];
		int rnow, cnow;
		rnow = i+1;
		cnow = j;
		if (rnow < r && m[rnow][cnow] != -1 && m[rnow][cnow] != -3)
		{
			if (dist[rnow][cnow] > dist[i][j] + 1)
			{
				dist[rnow][cnow] = dist[i][j] + 1;
				q.push_back((rnow)*1000+cnow);
			}
		}
		rnow = i-1;
		if (rnow >= 0 && m[rnow][cnow] != -1 && m[rnow][cnow] != -3)
		{
			if (dist[rnow][cnow] > dist[i][j] + 1)
			{
				dist[rnow][cnow] = dist[i][j] + 1;
				q.push_back((rnow)*1000+cnow);
			}
		}
		rnow = i;
		cnow = j+1;
		if (cnow < c && m[rnow][cnow] != -1 && m[rnow][cnow] != -3)
		{
			if (dist[rnow][cnow] > dist[i][j] + 1)
			{
				dist[rnow][cnow] = dist[i][j] + 1;
				q.push_back((rnow)*1000+cnow);
			}
		}
		cnow = j-1;
		if (cnow >= 0 && m[rnow][cnow] != -1 && m[rnow][cnow] != -3)
		{
			if (dist[rnow][cnow] > dist[i][j] + 1)
			{
				dist[rnow][cnow] = dist[i][j] + 1;
				q.push_back((rnow)*1000+cnow);
			}
		}
	}
	cout << battle_count;
	//cin >> c;
}


#pragma warning(disable:4996)

#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <set>
#include <vector>
#include <stack>
#include <assert.h>
#include <unordered_map>
#include <cmath>
#include <queue>

using namespace std;

typedef long long int i64;
typedef vector<int> vint;
typedef vector<i64> vi64;
typedef pair<int, int> pint;
typedef pair<i64, i64> pi64;

const i64 inf = 10000000000000000LL;
const i64 mod = 1000000007;

#define forn(i, n) for(int i = 0; i < (n); ++i)
#define down(i, n) for(int i = ((int)n)-1; i >= 0; --i)

#define CONTEST "box"

struct Node
{
    vint nbr;
    i64 v;

};

i64 dfs(vector<Node> & arr, int v, int d)
{
    if (d == 0)
    {
        forn(i, arr.size())
        {
            arr[i].v = 0;
        }
    }

    forn(i, arr[v].nbr.size())
    {
        int to = arr[v].nbr[i];
        if (d == 0)
            dfs(arr, to, d + 1);
        else
        {
            arr[to].v++;
        }
    }

    i64 ans = 0;
    if (d == 0)
    {
        forn(i, arr.size())
        {
            i64 v = arr[i].v;
            ans += v * (v - 1) / 2;
        }
        ans -= arr[v].v * (arr[v].v - 1) / 2;

    }
    return ans;
}

void check(int * d)
{
    d[8]--;
    d[9]--;
    d[1]--;
    d[6]--;
    vint arr(4);
    arr[0] = 1;
    arr[1] = 6;
    arr[2] = 8;
    arr[3] = 9;
    i64 c = 0;
    down(i, 10)
    {
        if (i == 0)
        {
            break;
        }
        forn(j, d[i])
        {
            c *= 10;
            c += i;
            c %= 7;
            cout << i;
        }
    }

    do
    {
        i64 k = c;
        forn(i, 4)
        {
            k *= 10;
            k += arr[i];
            k %= 7;
        }
        if (k == 0)
        {
            break;
        }

    } while (next_permutation(arr.begin(), arr.end()));
    forn(i, 4)
    {
        cout << arr[i];
    }
    forn(j, d[0])
    {
        cout << 0;
    }
}

struct St
{
    i64 first, second;
    i64 n;
    i64 p;

    bool operator<(const St & oth) const
    {
        if (first != oth.first)
        {
            return first < oth.first;
        }
        return second < oth.second;
    }
};

int step[4][2] = {{-1, 0}, {1,0}, {0,-1}, {0, 1}};

int main()
{
    srand(13);
    ios_base::sync_with_stdio(false);
    cout << fixed << setprecision(2);
    int start = clock();
#ifdef FILE_INPUT
    freopen("file.in", "r", stdin);
    freopen("file.out", "w", stdout);
#endif
    int r, c;
    cin >> r >> c;
    vector<string> arr(r);
    forn(i, r)
    {
        cin >> arr[i];
    }
    vector<vint> a(r, vint(c, 0));
    forn(i, r)
    {
        forn(j, c)
        {
            if (arr[i][j] == 'E')
            {
                queue<pint> q;
                q.push(pint(i, j));
                a[i][j] = 1;
                while (q.size() > 0)
                {
                    pint curr = q.front();
                    q.pop();
                    forn(k, 4)
                    {
                        int y = curr.first + step[k][0];
                        int x = curr.second + step[k][1];
                        if (x >= 0 && x < c)
                        {
                            if (y >= 0 && y < r)
                            {
                                if (arr[y][x] != 'T')
                                {
                                    if (a[y][x] == 0)
                                    {
                                        a[y][x] = a[curr.first][curr.second] + 1;
                                        q.push(pint(y, x));
                                    }
                                }

                            }
                        }
                    }
                }
            }
        }
    }
    int S = 0;
    forn(i, r)
    {
        forn(j, c)
        {
            if (arr[i][j] == 'S')
            {
                S = a[i][j];
            }
        }
    }
    int ans = 0;
    forn(i, r)
    {
        forn(j, c)
        {
            if (arr[i][j] >= '0' && arr[i][j] <= '9')
            {
                if (a[i][j] > 0 && a[i][j] <= S)
                {
                    ans += arr[i][j] - '0';
                }
            }
        }
    }
    cout << ans;

    return 0;
}


#include <iostream>
#include <vector>
#include <queue>
using namespace std;

int r, c;
char s[1001][1001];
queue <int> q;
int d[1000001];
bool was[1000001];
int dx[] = {1,0,-1,0};
int dy[] = {0,1,0,-1};
int ans;
int start;
vector<int> path;

bool possible(int x, int y)
{
    return x >= 0 && x < r && y >= 0 && y < c;
}

int main()
{
    cin >> r >> c;
    for (int i = 0; i < r; ++i)
        cin >> s[i];
    for (int i = 0; i < r; ++i)
        for (int j = 0; j < c; ++j)
            if (s[i][j] == 'S')
                start = i * c + j;
    for (int i = 0; i < r; ++i)
    {
        for (int j = 0; j < c; ++j)
            if (s[i][j] == 'E')
            {
                q.push(i * c + j);
                was[i * c + j] = true;
                while (!q.empty())
                {
                    int v = q.front();
                    int to;
                    q.pop();
                    for (int i = 0; i < 4; ++i)
                    {
                        if (possible(v / c + dx[i], v % c + dy[i]))
                        {
                            if (!was[to = (v / c + dx[i]) * c + v % c + dy[i]])
                            {
                                if (s[v / c + dx[i]][v % c + dy[i]] != 'T')
                                {
                                    was[to] = true;
                                    q.push(to);
                                    d[to] = d[v] + 1;
                                }
                            }
                        }
                    }
                }
                for (int k = 0; k < r; ++k)
                {
                    for (int l = 0; l < c; ++l)
                    {
                        if (isdigit(s[k][l]))
                        {
                            if (was[k * c + l])
                                if (d[start] >= d[k * c + l])
                                    ans += s[k][l] - '0';
                        }
                    }
                }
                cout << ans << endl;
            }
    }
    return 0;
}


#include <iostream>
#include <vector>
#include <queue>
using namespace std;

int r, c;
char s[1001][1001];
queue <int> q;
int d[1000001];
bool was[1000001];
int dx[] = {1,0,-1,0};
int dy[] = {0,1,0,-1};
int ans;
int start;
vector<int> path;

bool possible(int x, int y)
{
    return x >= 0 && x < r && y >= 0 && y < c;
}

int main()
{
    cin >> r >> c;
    for (int i = 0; i < r; ++i)
        cin >> s[i];
    for (int i = 0; i < r; ++i)
        for (int j = 0; j < c; ++j)
            if (s[i][j] == 'S')
                start = i * c + j;
    for (int i = 0; i < r; ++i)
    {
        for (int j = 0; j < c; ++j)
            if (s[i][j] == 'E')
            {
                q.push(i * c + j);
                was[i * c + j] = true;
                p[i * c + j] = -1;
                while (!q.empty())
                {
                    int v = q.front();
                    int to;
                    q.pop();
                    for (int i = 0; i < 4; ++i)
                    {
                        if (possible(v / c + dx[i], v % c + dy[i]))
                        {
                            if (!was[to = (v / c + dx[i]) * c + v % c + dy[i]])
                            {
                                if (s[v / c + dx[i]][v % c + dy[i]] != 'T')
                                {
                                    was[to] = true;
                                    q.push(to);
                                    d[to] = d[v] + 1;
                                }
                            }
                        }
                    }
                }
                for (int k = 0; k < r; ++k)
                {
                    for (int l = 0; l < c; ++l)
                    {
                        if (isdigit(s[k][l]))
                        {
                            if (was[k * c + l])
                                if (d[start] >= d[k * c + l])
                                    ans += s[k][l] - '0';
                        }
                    }
                }
                cout << ans << endl;
            }
    }
    return 0;
}


#include<iostream>
#include<cstdio>
#include<string>
#include<set>
#include<algorithm>
#include<vector>
#include<map>
#include<cmath>
#include<queue>
using namespace std;

string lab[1000];
int d[1000][1000];
int r, c;

queue<pair<int, int> > Q;

int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};

bool good(int L, int x, int y)
{
    if (x < 0 || y < 0 || x >= r || y >= c || lab[x][y] == 'T' || d[x][y] != -1)
        return 0;
    d[x][y] = L;
    return 1;
}

void BFS(int x, int y)
{
    d[x][y] = 0;
    Q.push(make_pair(x, y));

    while (!Q.empty())
    {
        x = (Q.front()).first;
        y = (Q.front()).second;
        Q.pop();

        for (int i = 0; i < 4; i++)
            if (good(d[x][y] + 1, x + dx[i], y + dy[i]))
                Q.push(make_pair(x + dx[i], y + dy[i]));
    }
}

int main()
{
    #ifdef LOCAL
        freopen("input.txt", "rt", stdin);
        freopen("output.txt", "wt", stdout);
    #endif

    cin >> r >> c;
    for (int i = 0; i < r; i++)
        cin >> lab[i];

    int x, y, sx, sy;
    for (int i = 0; i < r; i++)
        for (int j = 0; j < c; j++)
        {
            d[i][j] = -1;
            if (lab[i][j] == 'E')
            {
                x = i;
                y = j;
            }
            if (lab[i][j] == 'S')
            {
                sx = i;
                sy = j;
            }
        }

    BFS(x, y);
    int ans = 0;

    for (int i = 0; i < r; i++)
        for (int j = 0; j < c; j++)
            if (lab[i][j] >= '0' && lab[i][j] <= '9' && d[i][j] <= d[sx][sy])
                ans += lab[i][j] - '0';

    cout << ans;
}


#include<iostream>
#include<cstdio>
#include<string>
#include<set>
#include<algorithm>
#include<vector>
#include<map>
#include<cmath>
#include<queue>
using namespace std;

string lab[1000];
int d[1000][1000];
int r, c;

queue<pair<int, int> > Q;

int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};

bool good(int L, int x, int y)
{
    if (x < 0 || y < 0 || x >= r || y >= c || lab[x][y] == 'T' || d[x][y] != -1)
        return 0;
    d[x][y] = L;
    return 1;
}

void BFS(int x, int y)
{
    d[x][y] = 0;
    Q.push(make_pair(x, y));

    while (!Q.empty())
    {
        x = (Q.front()).first;
        y = (Q.front()).second;
        Q.pop();

        for (int i = 0; i < 4; i++)
            if (good(d[x][y] + 1, x + dx[i], y + dy[i]))
                Q.push(make_pair(x + dx[i], y + dy[i]));
    }
}

int main()
{
    #ifdef LOCAL
        freopen("input.txt", "rt", stdin);
        freopen("output.txt", "wt", stdout);
    #endif

    cin >> r >> c;
    for (int i = 0; i < r; i++)
        cin >> lab[i];

    int x, y, sx, sy;
    for (int i = 0; i < r; i++)
        for (int j = 0; j < c; j++)
        {
            d[i][j] = -1;
            if (lab[i][j] == 'E')
            {
                x = i;
                y = j;
            }
            if (lab[i][j] == 'S')
            {
                sx = i;
                sy = j;
            }
        }

    BFS(x, y);
    int ans = 0;

    for (int i = 0; i < r; i++)
        for (int j = 0; j < c; j++)
            if (lab[i][j] >= '0' && lab[i][j] <= '9' && d[i][j] <= d[sx][sy] && d[i][j] != -1)
                ans += lab[i][j] - '0';

    cout << ans;
}


#pragma comment(linker,"/STACK:650000000")
#include <iostream>
#include <cstdio>
#include <bitset>
#include <memory>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <list>
#include <string>
#include <cstring>
#include <fstream>
#include <functional>
#include <stack>
#include <wchar.h>
#include <wctype.h>
#include <cmath>
#include <queue>
#include <ctime>
#include <numeric>
#include <assert.h>

using namespace std;

template<typename T> T mabs(const T &a){ return a<0?-a:a;}
#define rep(x,y,z) for(int x=(y),e##x=(z);x<e##x;x++)
#define SQR(x) ((x)*(x))
#define all(c) (c).begin(), (c).end()

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef unsigned int ui;
typedef short int si;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;

char A[1010][1010];

int dx[]={-1,0,1,0};
int dy[]={0,-1,0,1};

int D[1010][1010];
void bfs(int x,int y,int n,int m)
{
	queue<pii> q;
	q.push(pii(x,y));
	memset(D,-1,sizeof(D));
	D[x][y] = 0;
	while (!q.empty())
	{
		x = q.front().first;
		y = q.front().second;
		q.pop();
		rep(k,0,4)
		{
			int nx = x+dx[k];
			int ny = y+dy[k];
			if (nx>=0 && nx<n && ny>=0 && ny<m && D[nx][ny]==-1 && A[nx][ny]!='T')
			{
				D[nx][ny] = D[x][y]+1;
				q.push(pii(nx,ny));
			}
		}
	}
}

void run()
{
	int n,m;
	cin>>n>>m;
	rep(i,0,n)
		scanf("%s",A[i]);
	int ex,ey;
	int sx,sy;
	rep(i,0,n)
		rep(j,0,m)
		if (A[i][j]=='E')
		{
			ex=i;
			ey=j;
		}
		else if (A[i][j]=='S')
		{
			sx = i;
			sy = j;
		}
	bfs(ex,ey,n,m);
	int res = 0;
	rep(i,0,n)
		rep(j,0,m)
			if (isdigit(A[i][j]) && D[i][j]<=D[sx][sy])
				res+=A[i][j]-'0';
	cout<<res<<endl;
}

//#define problem "party"

int main()
{
#ifdef _MONYURA_
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	time_t st=clock();
#else
	//freopen(problem".in","r",stdin);
	//freopen(problem".out","w",stdout);
#endif
	run();
#ifdef _MONYURA_
	printf("=============\n");
	printf("Time: %.2lf sec\n",(clock()-st)/double(CLOCKS_PER_SEC));
#endif

	return 0;
}


#pragma comment(linker,"/STACK:650000000")
#include <iostream>
#include <cstdio>
#include <bitset>
#include <memory>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <list>
#include <string>
#include <cstring>
#include <fstream>
#include <functional>
#include <stack>
#include <wchar.h>
#include <wctype.h>
#include <cmath>
#include <queue>
#include <ctime>
#include <numeric>
#include <assert.h>

using namespace std;

template<typename T> T mabs(const T &a){ return a<0?-a:a;}
#define rep(x,y,z) for(int x=(y),e##x=(z);x<e##x;x++)
#define SQR(x) ((x)*(x))
#define all(c) (c).begin(), (c).end()

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef unsigned int ui;
typedef short int si;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;

char A[1010][1010];

int dx[]={-1,0,1,0};
int dy[]={0,-1,0,1};

int D[1010][1010];
void bfs(int x,int y,int n,int m)
{
	queue<pii> q;
	q.push(pii(x,y));
	memset(D,-1,sizeof(D));
	D[x][y] = 0;
	while (!q.empty())
	{
		x = q.front().first;
		y = q.front().second;
		q.pop();
		rep(k,0,4)
		{
			int nx = x+dx[k];
			int ny = y+dy[k];
			if (nx>=0 && nx<n && ny>=0 && ny<m && D[nx][ny]==-1 && A[nx][ny]!='T')
			{
				D[nx][ny] = D[x][y]+1;
				q.push(pii(nx,ny));
			}
		}
	}
}

void run()
{
	int n,m;
	cin>>n>>m;
	rep(i,0,n)
		scanf("%s",A[i]);
	int ex,ey;
	int sx,sy;
	rep(i,0,n)
		rep(j,0,m)
		if (A[i][j]=='E')
		{
			ex=i;
			ey=j;
		}
		else if (A[i][j]=='S')
		{
			sx = i;
			sy = j;
		}
	bfs(ex,ey,n,m);
	int res = 0;
	rep(i,0,n)
		rep(j,0,m)
			if (isdigit(A[i][j]) && D[i][j]<=D[sx][sy] && D[i][j]!=-1)
				res+=A[i][j]-'0';
	cout<<res<<endl;
}

//#define problem "party"

int main()
{
#ifdef _MONYURA_
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	time_t st=clock();
#else
	//freopen(problem".in","r",stdin);
	//freopen(problem".out","w",stdout);
#endif
	run();
#ifdef _MONYURA_
	printf("=============\n");
	printf("Time: %.2lf sec\n",(clock()-st)/double(CLOCKS_PER_SEC));
#endif

	return 0;
}


/* practice with Dukkha */
#include <stdio.h>
#include <string.h>

#define N	1000
#define M	1000
#define INF	0x3f3f3f3f

char cc[N][M + 1];
int dd[N][M], n, m;

int parse(int i, int j) {
	char c;

	if (i < 0 || i >= n || j < 0 || j >= m || dd[i][j] != INF)
		return -1;
	c = cc[i][j];
	return c >= '0' && c <= '9' ? c - '0' : c == 'S' ? 0 : -1;
}

int di[4] = { -1, 1, 0, 0 };
int dj[4] = { 0, 0, -1, 1 };

int main() {
	static int kk[N * M], qq[N * M * 2];
	int h, i, i_, j, j_, k, d, head, cnt;

	scanf("%d%d", &n, &m);
	for (i = 0; i < n; i++)
		scanf("%s", cc[i]);
	for (i = 0; i < n; i++)
		for (j = 0; j < m; j++)
			if (cc[i][j] == 'E')
				goto outE;
outE:
	memset(dd, 0x3f, sizeof dd);
	head = cnt = 0;
	dd[i][j] = 0;
	qq[head + cnt++] = i;
	qq[head + cnt++] = j;
	while (cnt > 0) {
		i = qq[head++]; cnt--;
		j = qq[head++]; cnt--;
		d = dd[i][j] + 1;
		for (h = 0; h < 4; h++) {
			i_ = i + di[h];
			j_ = j + dj[h];
			k = parse(i_, j_);
			if (k >= 0) {
				kk[d] += k;
				dd[i_][j_] = d;
				qq[head + cnt++] = i_;
				qq[head + cnt++] = j_;
			}
		}
	}
	for (d = 1; d < n * m; d++)
		kk[d] += kk[d - 1];
	for (i = 0; i < n; i++)
		for (j = 0; j < m; j++)
			if (cc[i][j] == 'S')
				goto outS;
outS:
	printf("%d\n", kk[dd[i][j]]);
	return 0;
}


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
struct forest
{
    char status;//'0'~'9' is breaders_num, 'T' is tree,'S is startpos ,'E' is exit
}Forest[1010][1010];//init 1000 * 1000

struct queue
{
    int row;
    int col;
    int step;
    struct queue *next;
};

int create_path(int start[2],int exit[2],int step_cond,int max_step);

int main(int argc, char const *argv[])
{
    int row,col;
    scanf("%d%d",&row,&col);
    char get_endl;
    int exit[2],start[2];
    scanf("%c",&get_endl);
    for (int i = 0; i < row+2; ++i)
    {
        if (i==0 || i==row+1){
            for (int j = 0; j < col+2; ++j)
                Forest[i][j].status='T';
            continue;
        }
        Forest[i][0].status='T';
        Forest[i][col+1].status='T';//set edge to tree
        for (int j = 1; j < col+1; ++j){
            scanf("%c",&(Forest[i][j].status));
            // printf("get status : %c,%d,%d\n",Forest[i][j].status,i,j );
            if(Forest[i][j].status=='S'){
                start[0]=i;
                start[1]=j;
            }
            if(Forest[i][j].status=='E'){
                exit[0]=i;
                exit[1]=j;
            }
        }
        scanf("%c",&get_endl);
    }
    char walked_map[1010][1010]={{0}};//set zero
    int step;
    step=create_path(start,exit,0,0);
    // printf("step is %d\n",step );
    printf("%d\n",create_path(exit,exit,1,step));
    return 0;
}
// using bfs
struct queue *add_queue(struct queue *start_Queue,int row,int col,int step){
    if (start_Queue==NULL){
        start_Queue=(struct queue*)malloc(sizeof(struct queue));
        start_Queue->row=row;
        start_Queue->col=col;
        start_Queue->step=step;
        start_Queue->next=NULL;
        return start_Queue;
    }
    start_Queue->next=add_queue(start_Queue->next,row,col,step);
    return start_Queue;

}
int create_path(int start[2],int exit[2],int step_cond,int max_step){
    // printf("start[0] is %d,[1] is %d\n",start[0],start[1] );
    char forest_walked[1010][1010]={{0}};
    struct queue *start_Queue=(struct queue*)malloc(sizeof(struct queue));//init
    start_Queue->row=start[0];
    start_Queue->col=start[1];
    (start_Queue->step)=0;
    start_Queue->next=NULL;
    struct queue *last_queue;
    int array[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
    forest_walked[start[0]][start[1]]=1;//set walked
    if (step_cond==1)
    {
        int battlers=0,now_step=0;
        while((start_Queue->step)<max_step)
        {
            // printf("in\n");
            for (int i = 0; i < 4; ++i)
            {
                int row=(start_Queue->row)+array[i][0],col=(start_Queue->col)+array[i][1];
                if ((Forest[row][col].status)!='T' && forest_walked[row][col]==0){
                    if (isdigit(Forest[row][col].status)){//is 0 ~ 9
                        battlers+=((Forest[row][col].status)-'0');
                        // printf("add %d\n",(Forest[row][col].status)-'0' );
                    }
                    forest_walked[row][col]=1;
                    start_Queue= add_queue(start_Queue,row,col,(start_Queue->step)+1);
                }
            }
            assert(start_Queue!=NULL);
            last_queue=start_Queue;
            start_Queue=start_Queue->next;
            free(last_queue);
            assert(start_Queue!=NULL);
        }
        return battlers;
    }

    for(;;)
    {
        assert(start_Queue!=NULL);
        if (start_Queue->row==exit[0]&&start_Queue->col==exit[1])
            return start_Queue->step;
        for (int i = 0; i < 4; ++i)
        {
            // printf("ready\n");
            int row=(start_Queue->row)+array[i][0],col=(start_Queue->col)+array[i][1];
            // printf("now row: %d, col: %d\n",row,col );
            // if ((Forest[row][col].status)=='T')
            //     printf("T\n");
            // if (forest_walked[row][col]==1)
            //     printf("Walked\n");
            if ((Forest[row][col].status)!='T' && forest_walked[row][col]==0){
                // printf("get\n");
                forest_walked[row][col]=1;
                // for (int i = 0; i < 5; ++i)
                // {
                //     for (int j = 0; j < 5; ++j)
                //     {
                //         printf("%d ",forest_walked[i][j] );
                //     }
                //     printf("\n");
                // }
                start_Queue= add_queue(start_Queue,row,col,start_Queue->step+1);
            }
        }
        last_queue=start_Queue;
        start_Queue=start_Queue->next;
        free(last_queue);
    }
    printf("error! create_path\n");
}


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
struct forest
{
    char status;//'0'~'9' is breaders_num, 'T' is tree,'S is startpos ,'E' is exit
}Forest[1010][1010];//init 1000 * 1000

struct queue
{
    int row;
    int col;
    int step;
    struct queue *next;
};

int create_path(int start[2],int exit[2],int step_cond,int max_step);

int main(int argc, char const *argv[])
{
    int row,col;
    scanf("%d%d",&row,&col);
    char get_endl;
    int exit[2],start[2];

    for (int i = 0; i < row+2; ++i)
    {
        if (i==0 || i==row+1){
            for (int j = 0; j < col+2; ++j)
                Forest[i][j].status='T';
            continue;
        }
        Forest[i][0].status='T';
        Forest[i][col+1].status='T';//set edge to tree
        for (int j = 1; j < col+1; ++j){
            scanf("%c",&(Forest[i][j].status));
            if(Forest[i][j].status=='S'){
                start[0]=i;
                start[1]=j;
            }
            if(Forest[i][j].status=='E'){
                exit[0]=i;
                exit[1]=j;
            }
        }
        scanf("%c",&get_endl);
    }
    char walked_map[1010][1010]={{0}};//set zero
    int step;
    step=create_path(start,exit,0,0);
    printf("%d\n",create_path(exit,exit,1,step));
    return 0;
}
// using bfs
struct queue *add_queue(struct queue *start_Queue,int row,int col,int step){
    if (start_Queue==NULL){
        start_Queue=(struct queue*)malloc(sizeof(struct queue));
        start_Queue->row=row;
        start_Queue->col=col;
        start_Queue->step=step;
        start_Queue->next=NULL;
        return start_Queue;
    }
    start_Queue->next=add_queue(start_Queue->next,row,col,step);
    return start_Queue;

}
int create_path(int start[2],int exit[2],int step_cond,int max_step){
    char forest_walked[1010][1010]={{0}};
    struct queue *start_Queue=(struct queue*)malloc(sizeof(struct queue));//init
    start_Queue->row=start[0];
    start_Queue->col=start[1];
    (start_Queue->step)=0;
    start_Queue->next=NULL;
    struct queue *last_queue;
    int array[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
    forest_walked[start[0]][start[1]]=1;//set walked
    if (step_cond==1)
    {
        int battlers=0,now_step=0;
        while((start_Queue->step)<=max_step)
        {
            for (int i = 0; i < 4; ++i)
            {
                int row=(start_Queue->row)+array[i][0],col=(start_Queue->col)+array[i][1];
                if ((Forest[row][col].status)!='T' && forest_walked[row][col]==0){
                    if (isdigit(Forest[row][col].status))//is 0 ~ 9
                        battlers+=((Forest[row][col].status)-'0');
                    forest_walked[row][col]=1;
                    start_Queue= add_queue(start_Queue,row,col,(start_Queue->step)+1);
                }
            }
            assert(start_Queue!=NULL);
            last_queue=start_Queue;
            start_Queue=start_Queue->next;
            free(last_queue);
            assert(start_Queue!=NULL);
        }
        return battlers;
    }

    for(;;)
    {
        if (start_Queue->row==exit[0]&&start_Queue->col==exit[1])
            return start_Queue->step;
        for (int i = 0; i < 4; ++i)
        {
            int row=(start_Queue->row)+array[i][0],col=(start_Queue->col)+array[i][1];
            if ((Forest[row][col].status)!='T' && forest_walked[row][col]==0){
                forest_walked[row][col]=1;
                start_Queue= add_queue(start_Queue,row,col,start_Queue->step+1);
            }
        }
        last_queue=start_Queue;
        start_Queue=start_Queue->next;
        free(last_queue);
    }
    printf("error! create_path\n");
}


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
struct forest
{
    char status;//'0'~'9' is breaders_num, 'T' is tree,'S is startpos ,'E' is exit
}Forest[1010][1010];//init 1000 * 1000

struct queue
{
    int row;
    int col;
    int step;
    struct queue *next;
};

int create_path(int start[2],int exit[2],int step_cond,int max_step);

int main(int argc, char const *argv[])
{
    int row,col;
    scanf("%d%d",&row,&col);
    char get_endl;
    int exit[2],start[2];
    scanf("%c",&get_endl);
    for (int i = 0; i < row+2; ++i)
    {
        if (i==0 || i==row+1){
            for (int j = 0; j < col+2; ++j)
                Forest[i][j].status='T';
            continue;
        }
        Forest[i][0].status='T';
        Forest[i][col+1].status='T';//set edge to tree
        for (int j = 1; j < col+1; ++j){
            scanf("%c",&(Forest[i][j].status));
            // printf("get status : %c,%d,%d\n",Forest[i][j].status,i,j );
            if(Forest[i][j].status=='S'){
                start[0]=i;
                start[1]=j;
            }
            if(Forest[i][j].status=='E'){
                exit[0]=i;
                exit[1]=j;
            }
        }
        scanf("%c",&get_endl);
    }
    char walked_map[1010][1010]={{0}};//set zero
    int step;
    step=create_path(start,exit,0,0);
    // printf("step is %d\n",step );
    printf("%d\n",create_path(exit,exit,1,step));
    return 0;
}
// using bfs
struct queue *add_queue(struct queue *start_Queue,int row,int col,int step){
    if (start_Queue==NULL){
        start_Queue=(struct queue*)malloc(sizeof(struct queue));
        start_Queue->row=row;
        start_Queue->col=col;
        start_Queue->step=step;
        start_Queue->next=NULL;
        return start_Queue;
    }
    start_Queue->next=add_queue(start_Queue->next,row,col,step);
    return start_Queue;

}
struct queue *init_queue(int row,int col,int step){
    struct queue *start_Queue=(struct queue*)malloc(sizeof(struct queue));//init
    // printf("init %p\n",start_Queue );
    start_Queue->row=row;
    start_Queue->col=col;
    start_Queue->step=step;
    start_Queue->next=NULL;
    return start_Queue;
}
int create_path(int start[2],int exit[2],int step_cond,int max_step){
    // printf("start[0] is %d,[1] is %d\n",start[0],start[1] );
    char forest_walked[1010][1010]={{0}};
    struct queue *start_Queue=(struct queue*)malloc(sizeof(struct queue));//init
    start_Queue->row=start[0];
    start_Queue->col=start[1];
    (start_Queue->step)=0;
    start_Queue->next=NULL;
    struct queue *end_queue=start_Queue;
    struct queue *last_queue;
    int array[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
    forest_walked[start[0]][start[1]]=1;//set walked
    if (step_cond==1)
    {
        int battlers=0,now_step=0;
        while((start_Queue->step)<max_step)
        {
            // printf("in\n");
            for (int i = 0; i < 4; ++i)
            {
                int row=(start_Queue->row)+array[i][0],col=(start_Queue->col)+array[i][1];
                if ((Forest[row][col].status)!='T' && forest_walked[row][col]==0){
                    if (isdigit(Forest[row][col].status)){//is 0 ~ 9
                        battlers+=((Forest[row][col].status)-'0');
                        // printf("add %d\n",(Forest[row][col].status)-'0' );
                    }
                    forest_walked[row][col]=1;
                    end_queue->next= init_queue(row,col,(start_Queue->step)+1);
                    end_queue=end_queue->next;
                }
            }
            assert(start_Queue!=NULL);
            last_queue=start_Queue;
            start_Queue=start_Queue->next;
            free(last_queue);
            assert(start_Queue!=NULL);
        }
        return battlers;
    }

    for(;;)
    {
        assert(start_Queue!=NULL);
        if (start_Queue->row==exit[0]&&start_Queue->col==exit[1])
            return start_Queue->step;
        for (int i = 0; i < 4; ++i)
        {
            // printf("ready\n");
            int row=(start_Queue->row)+array[i][0],col=(start_Queue->col)+array[i][1];
            // printf("now row: %d, col: %d\n",row,col );
            // if ((Forest[row][col].status)=='T')
            //     printf("T\n");
            // if (forest_walked[row][col]==1)
            //     printf("Walked\n");
            if ((Forest[row][col].status)!='T' && forest_walked[row][col]==0){
                // printf("get\n");
                forest_walked[row][col]=1;
                // for (int i = 0; i < 5; ++i)
                // {
                //     for (int j = 0; j < 5; ++j)
                //     {
                //         printf("%d ",forest_walked[i][j] );
                //     }
                //     printf("\n");
                // }
                end_queue->next= init_queue(row,col,(start_Queue->step)+1);
                end_queue=end_queue->next;
            }
        }
        last_queue=start_Queue;
        start_Queue=start_Queue->next;
        free(last_queue);
    }
    printf("error! create_path\n");
}


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
struct forest
{
    char status;//'0'~'9' is breaders_num, 'T' is tree,'S is startpos ,'E' is exit
}Forest[1010][1010];//init 1000 * 1000

struct queue
{
    int row;
    int col;
    int step;
    struct queue *next;
};

int create_path(int start[2],int exit[2],int step_cond,int max_step);

int main(int argc, char const *argv[])
{
    int row,col;
    scanf("%d%d",&row,&col);
    char get_endl;
    int exit[2],start[2];
    scanf("%c",&get_endl);
    for (int i = 0; i < row+2; ++i)
    {
        if (i==0 || i==row+1){
            for (int j = 0; j < col+2; ++j)
                Forest[i][j].status='T';
            continue;
        }
        Forest[i][0].status='T';
        Forest[i][col+1].status='T';//set edge to tree
        for (int j = 1; j < col+1; ++j){
            scanf("%c",&(Forest[i][j].status));
            // printf("get status : %c,%d,%d\n",Forest[i][j].status,i,j );
            if(Forest[i][j].status=='S'){
                start[0]=i;
                start[1]=j;
            }
            if(Forest[i][j].status=='E'){
                exit[0]=i;
                exit[1]=j;
            }
        }
        scanf("%c",&get_endl);
    }
    char walked_map[1010][1010]={{0}};//set zero
    int step;
    step=create_path(start,exit,0,0);
    printf("%d\n",create_path(exit,exit,1,step));
    return 0;
}
// using bfs
struct queue *add_queue(struct queue *start_Queue,int row,int col,int step){
    if (start_Queue==NULL){
        start_Queue=(struct queue*)malloc(sizeof(struct queue));
        start_Queue->row=row;
        start_Queue->col=col;
        start_Queue->step=step;
        start_Queue->next=NULL;
        return start_Queue;
    }
    start_Queue->next=add_queue(start_Queue->next,row,col,step);
    return start_Queue;

}
int create_path(int start[2],int exit[2],int step_cond,int max_step){
    // printf("start[0] is %d,[1] is %d\n",start[0],start[1] );
    char forest_walked[1010][1010]={{0}};
    struct queue *start_Queue=(struct queue*)malloc(sizeof(struct queue));//init
    start_Queue->row=start[0];
    start_Queue->col=start[1];
    (start_Queue->step)=0;
    start_Queue->next=NULL;
    struct queue *last_queue;
    int array[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
    forest_walked[start[0]][start[1]]=1;//set walked
    if (step_cond==1)
    {
        int battlers=0,now_step=0;
        while((start_Queue->step)<=max_step)
        {
            for (int i = 0; i < 4; ++i)
            {
                int row=(start_Queue->row)+array[i][0],col=(start_Queue->col)+array[i][1];
                if ((Forest[row][col].status)!='T' && forest_walked[row][col]==0){
                    if (isdigit(Forest[row][col].status))//is 0 ~ 9
                        battlers+=((Forest[row][col].status)-'0');
                    forest_walked[row][col]=1;
                    start_Queue= add_queue(start_Queue,row,col,(start_Queue->step)+1);
                }
            }
            assert(start_Queue!=NULL);
            last_queue=start_Queue;
            start_Queue=start_Queue->next;
            free(last_queue);
            assert(start_Queue!=NULL);
        }
        return battlers;
    }

    for(;;)
    {
        assert(start_Queue!=NULL);
        if (start_Queue->row==exit[0]&&start_Queue->col==exit[1])
            return start_Queue->step;
        for (int i = 0; i < 4; ++i)
        {
            // printf("ready\n");
            int row=(start_Queue->row)+array[i][0],col=(start_Queue->col)+array[i][1];
            // printf("now row: %d, col: %d\n",row,col );
            // if ((Forest[row][col].status)=='T')
            //     printf("T\n");
            // if (forest_walked[row][col]==1)
            //     printf("Walked\n");
            if ((Forest[row][col].status)!='T' && forest_walked[row][col]==0){
                // printf("get\n");
                forest_walked[row][col]=1;
                // for (int i = 0; i < 5; ++i)
                // {
                //     for (int j = 0; j < 5; ++j)
                //     {
                //         printf("%d ",forest_walked[i][j] );
                //     }
                //     printf("\n");
                // }
                start_Queue= add_queue(start_Queue,row,col,start_Queue->step+1);
            }
        }
        last_queue=start_Queue;
        start_Queue=start_Queue->next;
        free(last_queue);
    }
    printf("error! create_path\n");
}


#include <stdio.h>
#ifndef Max_len
#define Max_len 1000
#endif
struct forest
{
    char status;//'0'~'9' is breaders_num, 'T' is tree,'S is startpos ,'E' is exit
}Forest[1010][1010];//init 1000 * 1000

struct queue
{
    int row;
    int col;
    struct queue *next;
};

void create_path(int N_row,int N_col,int exit[2],int step,char walked_map[1010][1010]);
int find_battlers(int N_row,int N_col,int step,struct queue *now_end,struct queue Queue){
    //using bfs
    for (int i = 0; i < step; ++i)
    {

    }
}

int row,col;
int Max=-1;

int main(int argc, char const *argv[])
{
    scanf("%d%d",&row,&col);
    char get_endl;
    int exit[2],start[2];
    for (int i = 0; i < row+2; ++i)
    {
        if (i==0 || i==row+1){
            for (int j = 0; j < col+2; ++j)
                Forest[i][j].status='T';
            continue;
        }
        Forest[i][0].status='T';
        Forest[i][col+1].status='T';//set edge to tree
        for (int j = 1; j < col+1; ++j){
            scanf("%c",Forest[i][j].status);
            if(Forest[i][j].status=='S'){
                start[0]=i;
                start[1]=j;
            }
            if(Forest[i][j].status=='E'){
                exit[0]=i;
                exit[1]=j;
            }
        }
        scanf("%c",&get_endl);
    }
    char walked_map[1010][1010]={{0}};//set zero
    create_path();
    return 0;
}

void create_path(int N_row,int N_col,int exit[2],int step,char walked_map[1010][1010]){
    if (Forest[N_row][N_col].status='T'||walked_map[N_row][N_col]==1)
        return;
    if (N_row==exit[0]&&N_col==exit[1])//go to the exit
    {
        struct queue Queue;
        Queue.row=N_row;
        Queue.col=N_col;
        Queue.next=NULL;
        struct queue *now_queue=Queue;
        battle_sum=find_battlers(N_row,N_col,step,now_queue,Queue);
        if (Max==-1)
            Max=battle_sum;
        else{
            if (battle_sum<Max)
            Max=battle_sum;
        }
    }
    walked_map[N_row][N_col]=1;
    create_path(N_row+1,N_col,exit,step+1,walked_map);
    create_path(N_row-1,N_col,exit,step+1,walked_map);
    create_path(N_row,N_col+1,exit,step+1,walked_map);
    create_path(N_row,N_col-1,exit,step+1,walked_map);
}


#[allow(unused_imports)] use std::{*, io::*, cmp::*, char::*, collections::*, mem::* };
#[allow(unused)] macro_rules! input { ($($r:tt)*) => { let stdin = std::io::stdin(); let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock())); let mut next = move || -> String{ bytes.by_ref().map(|r|r.unwrap() as char).skip_while(|c|c.is_whitespace()).take_while(|c|!c.is_whitespace()).collect() }; input_inner!{next, $($r)*} }; }
#[allow(unused)] macro_rules! input_inner { ($next:expr) => {}; ($next:expr, ) => {}; ($next:expr, $var:ident : $t:tt $($r:tt)*) => { let $var = read_value!($next, $t); input_inner!{$next $($r)*} }; }
#[allow(unused)] macro_rules! read_value { ($next:expr, ( $($t:tt),* )) => { ( $(read_value!($next, $t)),* ) }; ($next:expr, [ $t:tt ; $len:expr ]) => { (0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>() }; ($next:expr, chars) => { read_value!($next, String).chars().collect::<Vec<char>>() }; ($next:expr, usize1) => { read_value!($next, usize) - 1}; ($next:expr, [ $t:tt ]) => {{ let len = read_value!($next, usize);(0..len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()}};($next:expr, $t:ty) => {$next().parse::<$t>().expect("Parse error")};}
#[allow(unused)] macro_rules! debug { ($($format:tt)*) => (write!(std::io::stderr(), $($format)*).unwrap()); }
#[allow(unused)] macro_rules! debugln { ($($format:tt)*) => (writeln!(std::io::stderr(), $($format)*).unwrap()); }

fn solve() {
    let out = std::io::stdout();
    let mut out = BufWriter::new(out.lock());
    #[allow(unused)] macro_rules! puts { ($($format:tt)*) => (let _ = write!(out,$($format)*);); }

    let r = get();
    let c = get();
    let mut a = vec![vec!['c'; c]; r];
    // also input! is buggy. . .
    for i in 0..r {
        a[i] = get_word().chars().collect(); // that's uncool. . . keep forgetting how to do this with input!
    }

    let find = |x| {
        for i in 0..r {
            for j in 0..c {
                if x == a[i][j] {
                    return Some((i, j));
                }
            }
        }
        return None;
    };

    let exit = find('E').unwrap();
    let start = find('S').unwrap();

    let mut dist = vec![vec![-1; c]; r];

    (|s| { // bfs
        let mut q = VecDeque::<(usize, usize)>::new();
        q.push_back(s);
        dist[s.0][s.1] = 0;
        loop {
            if q.len() == 0 { break; }
            let v = q.pop_front().unwrap();
            let mut one = (1, 0);
            for _ in 0..4 {
                let w = (v.0 as i64 + one.0, v.1 as i64 + one.1);
                if 0 <= w.0 && w.0 < r as i64
                && 0 <= w.1 && w.1 < c as i64 {
                    let w = (w.0 as usize, w.1 as usize);
                    if a[w.0][w.1] != 'T' && dist[w.0][w.1] == -1 {
                        dist[w.0][w.1] = dist[v.0][v.1] + 1;
                        q.push_back((w.0, w.1));
                    }
                }
                one = (-one.1, one.0);
            }
        }
    })(exit);

    let mut cnt = 0;
    for i in 0..r {
        for j in 0..c {
            if (i, j) != start && (i, j) != exit && a[i][j] != 'T' && -1 < dist[i][j] && dist[i][j] <= dist[start.0][start.1] {
                cnt += a[i][j] as i64 - '0' as i64;
            }
        }
    }
    print!("{}", cnt);
}
fn main() {
    // In order to avoid potential stack overflow, spawn a new thread.
    let stack_size = 104_857_600; // 100 MB
    let thd = std::thread::Builder::new().stack_size(stack_size);
    thd.spawn(|| solve()).unwrap().join().unwrap();
}

#[allow(dead_code)]
fn get_word() -> String {
      let stdin = std::io::stdin();
      let mut stdin=stdin.lock();
      let mut u8b: [u8; 1] = [0];
      loop {
          let mut buf: Vec<u8> = Vec::with_capacity(16);
          loop {
              let res = stdin.read(&mut u8b);
              if res.unwrap_or(0) == 0 || u8b[0] <= b' ' {
                  break;
              } else {
                  buf.push(u8b[0]);
              }
          }
          if buf.len() >= 1 {
              let ret = String::from_utf8(buf).unwrap();
              return ret;
          }
      }
}
#[allow(dead_code)]
fn get<T: std::str::FromStr>() -> T { get_word().parse().ok().unwrap() }

// https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8