#include <iostream>
#include <string>
#include <queue>
#include <algorithm>

using namespace std;

struct Grid {
	int x;
	int y;
};

int n, m, ans;
int direction[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
char c[1005][1005];
int vis[1005][1005];

//特别说明一下题目意思,因为确实描述很逆天,下面描述在原来的基础上做修正
//1.若某片区域四周(上下左右方向)均被围墙或地图边界包围,洪水无法渗入,该区域视为安全。——> 修正为:边界外都是洪水,与边界连通的区域都会被淹没
//2.请统计不会被洪水淹没的区域数量。 ———>修正为:统计未被淹没的区域的大小(未被淹没的'0'的数量,而不是连通块数量)

//每个点只入队列一遍
int main() {
	cin >> n >> m;
	cin.ignore();
	for (int i = 0; i < n; i++) {
		cin.getline(c[i], m + 1);
	}
	for(int i = 0; i < n; i++) {
		for(int j = 0;  j < m; j++) {
			if (!vis[i][j] && c[i][j] != '*') {
				int cnt = 0;
				bool flag = true;
				queue<Grid> q;				 
				Grid st;
				st.x = i;
				st.y = j;
				q.push(st);
				vis[st.x][st.y] = 1;
				while (!q.empty()) {
					Grid g = q.front();
					q.pop();
					if (g.x == 0 || g.y == 0 || g.x == n - 1 || g.y == m - 1) flag = false;
					cnt++;
					for (int k = 0; k < 4; k++) {
						int x = g.x + direction[k][0];
						int y = g.y + direction[k][1];
						if (x > -1 && x < n && y > -1 && y < m && !vis[x][y] && c[x][y] != '*') {
							vis[x][y] = 1;
							Grid new_grid;
							new_grid.x = x;
							new_grid.y = y;
							q.push(new_grid); 
						} 
					}
				}
				ans += flag ? cnt : 0; 
			}
  		}
	}
	cout << ans << endl;
}