#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

#define REP(i,n) for(int i=0;i<n;++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))

#define MOD 1000000007
#define INF 1000000000

#define MAX_H 2010
#define MAX_W MAX_H

int H, W;
string S[MAX_H];

// ヒストグラム(棒状グラフ)の中の最大長方形を求める
template<typename T>
class Hist {
    public:
        Hist(){}
        Hist(const T length) { Init(length); }
        ~Hist() { if(m_B != nullptr) { delete[] m_B; } }

        void Init(const T length) {
            m_B = new T[length+1];
            m_Length = length;
            for(T i = 0; i < length+1; ++i) { m_B[i] = 0; }
        }
        void Input(T i, T val) { m_B[i] = val; }
        void Disp() {
            for(T i = 0; i < m_Length+1; ++i) { printf("%lld ", m_B[i]); }
            printf("\n");
        }

        // ヒストグラムにある最大長方形の面積を返す
        // O(m_Length)
        T GetLargestRectangle() {
            stack<Rect> st;
            T maxv = 0;
            m_B[m_Length] = 0;

            for(T i = 0; i <= m_Length; ++i) {
                Rect rect;
                rect.height = m_B[i];
                rect.pos = i;
                if(st.empty()) {
                    st.push(rect);
                } else {
                    if(st.top().height < rect.height) {
                        st.push(rect);
                    } else if(st.top().height > rect.height) {
                        // 前より低くなったら、 rect と同じ高さになるまで長方形の面積計算ができる
                        T target = i;
                        while(!st.empty() && st.top().height >= rect.height) {
                            Rect pre = st.top(); st.pop();
                            T x = pre.height, y = (i - pre.pos);
                            x -= (x - 1) / 2;
                            y -= (y - 1) / 2;
                            T area = x * y;
                            maxv = max(maxv, area);
                            target = pre.pos;
                        }
                        rect.pos = target;  // 位置の更新
                        st.push(rect);
                    }
                }
            }
            return maxv;
        }
    private:
        struct Rect { T height; T pos; };

    private:
        T *m_B;        // ヒストグラム
        T m_Length;    // ヒストグラムの横軸の長さ
};

// 二次元グリッド白黒問題用
// 幅 * 高さが 10^7 くらいまではいける
// ヒストグラムの最大長方形アルゴリズムを利用
template <typename T>
class Grid2D {
    public:
        enum Color { WHITE = 0, BLACK = 1 };
        // グリッドを WHITE で初期化
        Grid2D(const T h, const T w) : m_H(h), m_W(w) {
            m_G = new T*[h];
            m_Hist = new Hist<int>[h];
            for(T i = 0; i < h; ++i) {
                m_Hist[i].Init(w);
                m_G[i] = new T[w];
                for(T j = 0; j < w; ++j) { m_G[i][j] = WHITE; }
            }
        }
        ~Grid2D() {
            for(T i = 0; i < m_H; ++i) { delete[] m_G[i]; }
            delete[] m_G;
            delete[] m_Hist;
        }
        void Disp() {
            for(T i = 0; i < m_H; ++i) {
                for(T j = 0; j < m_W; ++j) { printf("%c", (m_G[i][j] == WHITE) ? '.' : '#'); }
                printf("\n");
            }
        }

        // (i, j) の位置に c (Color) を入れる
        void Input(T i, T j, T c) { m_G[i][j] = c; }

        // 二次元グリッド上が白黒二色で塗られているときの
        // 白い最大長方形の辺の長さを返す
        // O(HW)
        T GetLargestRectangle() {
            // 各行の上方向へ連続するマスの数でヒストグラムを作成
            for(T j = 0; j < m_W; ++j) {
                T sequence = 0;
                for(T i = 0; i < m_H; ++i) {
                    if(m_G[i][j] == BLACK) {
                        sequence = 0;
                        m_Hist[i].Input(j, 0);
                    }
                    else {
                        sequence++;
                        m_Hist[i].Input(j, sequence);
                    }
                }
            }
            // それを元に最大長方形を導出
            T maxv = 0;
            for(T i = 0; i < m_H; ++i) { maxv = max(maxv, m_Hist[i].GetLargestRectangle()); }
            return maxv;
        }

    private:
        const T m_H, m_W;  // 高さと幅
        T** m_G;           // グリッドのデータ
        Hist<T>* m_Hist;
};

int main()
{
    cin >> H >> W;
    REP(i, H) { cin >> S[i]; }

    Grid2D<int> g2d(2 * H - 1, 2 * W - 1);
    // 2 * 2 ずつ見て、黒が奇数ならマークする
    REP(i, H-1) {
        REP(j, W-1) {
            int cnt = 0;
            if(S[i][j] == '#') { cnt++; }
            if(S[i+1][j] == '#') { cnt++; }
            if(S[i][j+1] == '#') { cnt++; }
            if(S[i+1][j+1] == '#') { cnt++; }
            if(cnt % 2 != 0) { g2d.Input(2 * i + 1, 2 * j + 1, Grid2D<int>::BLACK); }
        }
    }
    //g2d.Disp();
    printf("%d\n", g2d.GetLargestRectangle());
    return 0;
}


Measured memory_bytes: 131584