import std.stdio;
import std.c.stdio;
import std.range;
import std.array;
import std.functional;
import std.algorithm;
import std.conv;
import std.container;
import std.math;
import std.numeric;
import std.string;
import std.c.string;
import std.regex;
import std.typecons;

bool get(int bit, int i) {
    return ((bit & (1 << i)) > 0);
}

int set(int bit, int i, bool x) {
    if (x) {
        return (bit | (1 << i));
    } else {
        return (bit & (~(1 << i)));
    }
}
 
void main() {
    int M, N; scanf("%d %d\n", &M, &N);
    char[][] F;
    foreach (i; 0 .. M) { F ~= cast(char[])(readln.chomp); }

    const MOD = 100000;

    auto pow3 = new int[401];
    pow3[0] = 1;
    foreach (i; 1 .. 401) {
        pow3[i] = (pow3[i - 1] * 3) % MOD;
    }

    int count(int y, int x) {
        int C = 0;
        foreach (j; x + 1 .. N) {
            if (F[y][j] == '?') C++;
        }
        foreach (i; y + 1 .. M) {
            foreach (j; 0 .. N) {
                if (F[i][j] == '?') C++;
            }
        }
        //writeln("count -> ", pow3[C]);
        return pow3[C];
    }

    bool jo(int y, int x) {
        if (y - 1 < 0) return false;
        if (x + 1 >= N) return false;
        return F[y - 1][x] == 'J' && F[y - 1][x + 1] == 'O';
    }

    int[int] id;
    void prepare() {
        int C = 0;
        void dfs(int x, int used) {
            if (x >= N) {
                id[used] = C++;
            } else {
                used = used.set(x, true);
                dfs(x + 2, used);
                used = used.set(x, false);
                dfs(x + 1, used);
            }
        }
        dfs(0, 0);
    }
    prepare();

    auto memo = new int[][][][](2, M, N, id.length);
    foreach (i; 0 .. 2) foreach (j; 0 .. M) foreach (k; 0 .. N)
        memo[i][j][k][] = -1;
    int dfs(int y, int x, int bit, bool prev_j) {
        //writefln("(%d, %d), %b, %b", y, x, bit, prev_j);
        //alias memoize!raw_dfs dfs;
        //alias raw_dfs dfs;
        if (y == M) return 0;
        int ret = 0;
        if (x == N) {
            return dfs(y + 1, 0, bit, false);
        }
        if (memo[prev_j][y][x][id[bit]] >= 0) {
            return memo[prev_j][y][x][id[bit]];
        }
        int bit_org = bit;
        if (F[y][x] == 'J') {
            ret = dfs(y, x + 1, bit.set(x, false), true);
        } else if (F[y][x] == 'O') {
            bit = bit.set(x, false);
            if (prev_j) {
                bit = bit.set(x - 1, true);
            }
            ret = dfs(y, x + 1, bit, false);
        } else if (F[y][x] == 'I') {
            if (bit.get(x)) {
                ret = count(y, x);
            } else {
                ret = dfs(y, x + 1, bit.set(x, false), false);
            }
        } else {
            // try 'I'
            if (bit.get(x)) {
                ret += count(y, x);
            } else {
                ret += dfs(y, x + 1, bit.set(x, false), false);
            }
            ret %= MOD;
            bit = bit.set(x, false);
            // try 'J'
            ret += dfs(y, x + 1, bit, true);
            ret %= MOD;
            // try 'O'
            if (prev_j) {
                ret += dfs(y, x + 1, bit.set(x - 1, true), false);
            } else {
                ret += dfs(y, x + 1, bit, false);
            }
            ret %= MOD;
        }
        return memo[prev_j][y][x][id[bit_org]] = ret;
    }

    dfs(0, 0, 0, false).writeln;
}