use std::collections::hash_map::Entry;
use std::hash::Hash;
use std::collections::hash_set::Iter;
use std::rc::Rc;
use std::ops::DivAssign;
use std::ops::MulAssign;
use std::ops::SubAssign;
use std::collections::BinaryHeap;
use std::str::FromStr;
use std::collections::HashSet;
use std::collections::BTreeMap;
use std::fmt::Display;
use std::ops::Neg;
use std::ops::Div;
use std::ops::Mul;
use std::ops::Add;
use std::ops::{AddAssign, Sub};
use std::cmp::max;
use std::collections::VecDeque;
use std::cmp::min;
use std::collections::{HashMap, BTreeSet};
use std::cmp::Ordering;
use std::fmt::Debug;

fn read_line() -> String {
    let mut buffer = String::new();
    std::io::stdin().read_line(&mut buffer).expect("No Line");
    buffer.trim().to_owned()
}
fn read_lines<T: std::str::FromStr>(count: usize) -> Vec<T> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(buffer.trim().parse().ok().expect("Can't Parse"));
        buffer.clear();
    }
    vec
}
fn read_tabulate<R, T: Fn(&str)->R> (count: usize, transformer: T) -> Vec<R> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(transformer(buffer.trim()));
        buffer.clear();
    }
    vec
}
fn read_value<T: std::str::FromStr>() -> T {
    read_line().trim().parse().ok().unwrap()
}
fn read_values<T: std::str::FromStr>() -> Vec<T> {
    read_line().trim().split_whitespace().map(|x| x.parse().ok().expect("Can't Parse")).collect::<Vec<T>>()
}
macro_rules! freeze {
    ($($id:ident), *) => {
        $(let $id = $id;)*
    };
}
macro_rules! read_map {
    ($ident: ident: [$block: block; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$block: block; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
}
macro_rules! read {
    (mut $ident: ident: String) => {
        let mut $ident = read_value::<String>();
    };
    ($ident: ident: String) => {
        let $ident = read_value::<String>();
    };
    (mut $ident: ident: [$ty:ty]) => {
        let mut $ident = read_values::<$ty>();
    };
    ($ident: ident: [$ty:ty]) => {
        let $ident = read_values::<$ty>();
    };
    (mut $ident: ident: [[$ty:ty]; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| read_values::<$ty>()).collect::<Vec<_>>();
    };
    ($ident: ident: [[$ty:ty]; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| read_values::<$ty>()).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$ty:ty; $size:expr]) => {
        let mut $ident = read_lines::<$ty>($size);
    };
    ($ident: ident: [$ty:ty; $size:expr]) => {
        let $ident = read_lines::<$ty>($size);
    };
    ($ident: ident: [$block: block; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$block: block; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    ($($token: tt)*) => {
        let mut iter = read_values::<String>().into_iter();
        read_from_iter!(iter; $($token)*);
    };
}
macro_rules! read_from_iter {
    ($iter:expr; mut $ident:ident:$ty:ty, $($rest:tt)*) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; $ident:ident:$ty:ty, $($rest:tt)*) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; mut $ident:ident:$ty:ty) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter:expr; $ident:ident:$ty:ty) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter: expr; ) => {};
}
struct KeyValue<K, V> {
    key: K,
    value: V
}
impl <K: PartialOrd, V> PartialEq for KeyValue<K, V> {
    fn eq(&self, other: &Self) -> bool {
        self.key.eq(&other.key)
    }
}
impl <K: PartialOrd, V> Eq for KeyValue<K, V> {}
impl <K: PartialOrd, V> PartialOrd for KeyValue<K, V> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.key.partial_cmp(&other.key)
    }
}
impl <K: PartialOrd, V> Ord for KeyValue<K, V> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.key.partial_cmp(&other.key).ok_or("Can't Compare").unwrap()
    }
}
#[derive(Eq, PartialEq)]
struct Rev<T: Ord>(T);
impl <T: std::cmp::Ord> PartialOrd for Rev<T> {
    fn partial_cmp(&self, rhs: &Rev<T>) -> std::option::Option<std::cmp::Ordering> { 
        rhs.0.partial_cmp(&self.0)
    }
}
impl <T: Ord> Ord for Rev<T> {
    fn cmp(&self, rhs: &Self) -> std::cmp::Ordering { 
        rhs.0.cmp(&self.0)
    }
}

const MOD: i64 = 100000;

#[derive(Clone, Debug)]
struct Flag {
    width: usize, height: usize,
    vec: Vec<Vec<Option<char>>>
}
#[derive(Clone, Debug)]
struct Position<'a> {
    x: usize, y: usize,
    flag: &'a Flag
}
#[derive(Copy, Clone, Debug)]
struct State {
    state: usize, last_j: bool
}
impl <'a> Position<'a> {
    fn new(flag: &Flag) -> Position {
        Position{x: 0, y: 0, flag: flag}
    }
    fn is_make_joi(&self, c: char, state: &State) -> bool {
        match c {
            'J' => false,
            'O' => false,
            'I' => (state.state >> (self.flag.width - 1)) != 0,
            _ => unreachable!()
        }
    }
    fn can_put(&self, c: char, state: State) -> bool {
        if self.end_state() {
            return false
        }
        if let Some(d) = self.flag.vec[self.y][self.x] {
            c == d && !self.is_make_joi(c, &state)
        }else {
            !self.is_make_joi(c, &state)
        }
    }
    fn put(&self, c: char, state: State) -> State {
        match c {
            'J' => State{state: (state.state << 1) & ((1 << self.flag.width) - 1), last_j: true},
            'O' => 
            if state.last_j && self.x > 0 {
                State{state: ((state.state + 1) << 1) & ((1 << self.flag.width) - 1), last_j: false}
            }else {
                State{state: (state.state << 1) & ((1 << self.flag.width) - 1), last_j: false}
            },
            'I' => State{state: (state.state << 1) & ((1 << self.flag.width) - 1), last_j: false},
            _ => unreachable!()
        }
    }
    fn move_to_next_pos(&mut self) {
        let next_x = (self.x + 1) % self.flag.width;
        let next_y = self.y + (self.x + 1) / self.flag.width;
        self.x = next_x;
        self.y = next_y;
    }
    fn end_state(&self) -> bool {
        self.y >= self.flag.height
    }
}
fn calc(flag: &Flag) -> i64 {
    let mut states = VecDeque::new();
    let mut position = Position{x: 0, y: 0, flag: flag};
    let mut memo = vec![vec![vec![0; 1 << flag.width]; 2]; 2];
    let mut version = vec![vec![0; 1 << flag.width]; 2];
    states.push_back(State{state:0, last_j: false});
    memo[1][0][0] = 1;
    let mut v = 0;
    let mut last = 0i64;
    while !position.end_state() {
        v += 1;
        last = 0;
        for _ in 0 .. states.len() {
            let front = states.pop_front().unwrap();
            let pattern = memo[v & 1][if front.last_j {1}else{0}][front.state];
            for c in "JOI".chars() {
                if position.can_put(c, front) {
                    let next = position.put(c, front);
                    if version[if next.last_j {1}else{0}][next.state] == v {
                        memo[(v & 1) ^ 1][if next.last_j {1}else {0}][next.state] = (memo[(v & 1) ^ 1][if next.last_j {1}else {0}][next.state] + pattern) % MOD;
                    }else {
                        version[if next.last_j {1}else{0}][next.state] = v;
                        memo[(v & 1) ^ 1][if next.last_j {1}else {0}][next.state] = pattern;
                        states.push_back(next);
                    }
                    last = (last + pattern) % MOD;
                }
            }
        }
        position.move_to_next_pos();
    }
    last
}
fn all_flag(flag: &Flag) -> i64 {
    let mut result = 1;
    for line in &flag.vec {
        for c in line {
            if c.is_none() {
                result = (result * 3) % MOD;
            }
        }
    }
    result
}
fn main() {
    read!(height: usize, width: usize);
    read_map!(flag: [{
        read!(line: String);
        line.chars().map(|c| {
            match c {
                '?' => None,
                _ => Some(c)
            }
        }).collect::<Vec<_>>()
    }; height]);
    let flag = Flag{height: height, width: width, vec: flag};
    println!("{}", (all_flag(&flag) + MOD - calc(&flag)) % MOD);
}



Measured memory_bytes: 54076