#include<bits/stdc++.h>
using namespace std;
const int N=102;
int gi() {
    int x=0,o=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if(ch=='-') o=-1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*o;
}
int n,m,x,y,ans=0,sx[N][N],sy[N][N];
short f[N][N][N][N];
int main() {
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) {
            char ch=getchar();
            while(ch!='.'&&ch!='o'&&ch!='E') ch=getchar();
            sx[i][j]=sy[i][j]=(ch=='o');
            sx[i][j]+=sx[i][j-1];sy[i][j]+=sy[i-1][j];
            if(ch=='E') x=i,y=j;
        }
    for(int i=x;i;i--)
        for(int j=y;j;j--)
            for(int k=x;k<=n;k++)
                for(int l=y;l<=m;l++) {
                    ans=max(ans,(int)f[i][j][k][l]);
                    if(i>1&&k+1<x+i) f[i-1][j][k][l]=max((int)f[i-1][j][k][l],f[i][j][k][l]+max(0,sx[i-1][min(l,m-y+j)]-sx[i-1][max(j-1,l-y)]));
                    if(k<n&&x+k<n+i) f[i][j][k+1][l]=max((int)f[i][j][k+1][l],f[i][j][k][l]+max(0,sx[k+1][min(l,m-y+j)]-sx[k+1][max(j-1,l-y)]));
                    if(j>1&&l+1<y+j) f[i][j-1][k][l]=max((int)f[i][j-1][k][l],f[i][j][k][l]+max(0,sy[min(k,n-x+i)][j-1]-sy[max(i-1,k-x)][j-1]));
                    if(l<m&&y+l<m+j) f[i][j][k][l+1]=max((int)f[i][j][k][l+1],f[i][j][k][l]+max(0,sy[min(k,n-x+i)][l+1]-sy[max(i-1,k-x)][l+1]));
                }
    printf("%d\n",ans);
    return 0;
}
//orzgzy
//鸡贼明年进队超稳


#include<iostream>
#include<math.h>
#include<algorithm>
#include<stdint.h>
#include<vector>
#include<deque>
#include<stack>
#include<functional>
#include<string>
#include<cstring>
#include<time.h>
#include<array>
#include<iomanip>
#include<list>
#include<set>
#include<map>
#include<random>
#include<unordered_map>
#include<unordered_set>
#include<bitset>
#include <queue>
#include<boost/multiprecision/cpp_int.hpp>


using namespace std;
using namespace boost::multiprecision;

using ll = long long;
using ull = unsigned long long;
using uint = unsigned int;
using ldb = long double;


//BDD,ZDD,kdtree, bdtree,bicalc, bolonoy, doloney, tree, chinesemod,segmenttree,daikusutora, saidairyuu, 2bugurahu, heirokenshutu, topologicalsort, kyourenketuseibun

#define REP(i,a,b) for(ll i = a; i < b; ++i)
#define PRI(s) cout << s << endl
#define PRIF(v, n) printf("%."#n"f\n", v)
#define PRIY PRI("Yes")
#define PRIN PRI("No")
template<typename A, typename B>
void mins(A & a, const B & b) { a = min(a, (A)b); };
template<typename A, typename B>
void maxs(A & a, const B & b) { a = max(a, (A)b); };

void factorize(ll X, vector<pair<ll,ll>>& ret) {
	for (ll i = 2; i * i <= X; ++i) {
		if (X % i != 0) continue;
		ret.push_back(pair<ll, ll>{i, 0});
		while (X % i == 0) {
			X /= i;
			ret.back().second++;
		}
	}
	if (X != 1) ret.push_back(pair<ll, ll>{X, 1});
}

int main() {
	ll mod = 1e9 + 7;
	ll N, M;
	cin >> N >> M;
	vector<vector<ll>> dp(N+1);
	vector<pair<ll, ll>> P;
	factorize(M, P);
	ll maxn = 0;
	for (const auto& p : P) maxs(maxn, p.second);
	REP(i, 0, N + 1) dp[i].resize(maxn + 1, 0);
	REP(i, 0, maxn + 1)dp[1][i] = 1;
	REP(i, 0, N + 1)dp[i][1] = i;
	REP(i, 2, N + 1) REP(j, 2, maxn + 1) dp[i][j] = (dp[i][j - 1] + dp[i - 1][j]) % mod;
	ll ans = 1;
	for (const auto& p : P) ans = ans * dp[N][p.second] % mod;
	PRI(ans);
	return 0;
}