#![allow(non_snake_case, unused)]
use std::collections::*;

////////// missing functions in 1.15.1 //////////
macro_rules! eprint {
	($($t:tt)*) => {{
		use ::std::io::Write;
		let _ = write!(::std::io::stderr(), $($t)*);
	}};
}
macro_rules! eprintln {
	() => { eprintln!(""); };
	($($t:tt)*) => {{
		use ::std::io::Write;
		let _ = writeln!(::std::io::stderr(), $($t)*);
	}};
}
macro_rules! dbg {
	($v:expr) => {{
		let val = $v;
		eprintln!("[{}:{}] {} = {:?}", file!(), line!(), stringify!($v), val);
		val
	}}
}
/////////////////////////////////////////////////
pub trait SetMinMax {
	fn setmin(&mut self, v: Self) -> bool;
	fn setmax(&mut self, v: Self) -> bool;
}
impl<T> SetMinMax for T where T: PartialOrd {
	fn setmin(&mut self, v: T) -> bool {
		*self > v && { *self = v; true }
	}
	fn setmax(&mut self, v: T) -> bool {
		*self < v && { *self = v; true }
	}
}

macro_rules! mat {
	($($e:expr),*) => { Vec::from(vec![$($e),*]) };
	($($e:expr,)*) => { Vec::from(vec![$($e),*]) };
	($e:expr; $d:expr) => { Vec::from(vec![$e; $d]) };
	($e:expr; $d:expr $(; $ds:expr)+) => { Vec::from(vec![mat![$e $(; $ds)*]; $d]) };
}

#[macro_export]
macro_rules! ok {
	($a:ident$([$i:expr])*.$f:ident()$(@$t:ident)*) => {
		$a$([$i])*.$f($($t),*)
	};
	($a:ident$([$i:expr])*.$f:ident($e:expr$(,$es:expr)*)$(@$t:ident)*) => { {
		let t = $e;
		ok!($a$([$i])*.$f($($es),*)$(@$t)*@t)
	} };
}

pub fn readln() -> String {
	let mut line = String::new();
	::std::io::stdin().read_line(&mut line).unwrap_or_else(|e| panic!("{}", e));
	line
}

macro_rules! read {
	($($t:tt),*; $n:expr) => {{
		let stdin = ::std::io::stdin();
		let ret = ::std::io::BufRead::lines(stdin.lock()).take($n).map(|line| {
			let line = line.unwrap();
			let mut it = line.split_whitespace();
			_read!(it; $($t),*)
		}).collect::<Vec<_>>();
		ret
	}};
	($($t:tt),*) => {{
		let line = readln();
		let mut it = line.split_whitespace();
		_read!(it; $($t),*)
	}};
}

macro_rules! _read {
	($it:ident; [char]) => {
		_read!($it; String).chars().collect::<Vec<_>>()
	};
	($it:ident; [u8]) => {
		Vec::from(_read!($it; String).into_bytes())
	};
	($it:ident; usize1) => {
		$it.next().unwrap_or_else(|| panic!("input mismatch")).parse::<usize>().unwrap_or_else(|e| panic!("{}", e)) - 1
	};
	($it:ident; [usize1]) => {
		$it.map(|s| s.parse::<usize>().unwrap_or_else(|e| panic!("{}", e)) - 1).collect::<Vec<_>>()
	};
	($it:ident; [$t:ty]) => {
		$it.map(|s| s.parse::<$t>().unwrap_or_else(|e| panic!("{}", e))).collect::<Vec<_>>()
	};
	($it:ident; $t:ty) => {
		$it.next().unwrap_or_else(|| panic!("input mismatch")).parse::<$t>().unwrap_or_else(|e| panic!("{}", e))
	};
	($it:ident; $($t:tt),+) => {
		($(_read!($it; $t)),*)
	};
}

pub fn main() {
	let _ = ::std::thread::Builder::new().name("run".to_string()).stack_size(32 * 1024 * 1024).spawn(run).unwrap().join();
}

use std::ops::*;
use std::marker::PhantomData;

pub trait Int {
	fn as_i32(self) -> i32;
	fn as_i64(self) -> i64;
	fn as_u32(self) -> u32;
	fn as_u64(self) -> u64;
	fn as_usize(self) -> usize;
}

macro_rules! impl_int {
	() => {};
	($t:ty $(, $ts:ty)*) => {
		impl Int for $t {
			fn as_i32(self) -> i32 {
				self as i32
			}
			fn as_i64(self) -> i64 {
				self as i64
			}
			fn as_u32(self) -> u32 {
				self as u32
			}
			fn as_u64(self) -> u64 {
				self as u64
			}
			fn as_usize(self) -> usize {
				self as usize
			}
		}
		impl_int!($($ts),*);
	}
}

impl_int!(i8, i16, i32, i64, u8, u16, u32, u64, isize, usize);

pub trait Mod: Copy + Default + Ord {
	fn m() -> u32;
}

#[derive(Clone, Copy, Default, Hash, PartialEq, PartialOrd, Eq, Ord)]
pub struct ModP<M>(pub u32, PhantomData<M>);

impl<M> ::std::fmt::Debug for ModP<M> {
	fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
		self.0.fmt(f)
	}
}

impl<M> ::std::fmt::Display for ModP<M> {
	fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
		self.0.fmt(f)
	}
}

impl<M: Mod> ModP<M> {
	/// Assume 0 <= a < m.
	pub fn new<I: Int>(a: I) -> ModP<M> {
		ModP(a.as_u32(), PhantomData)
	}
	pub fn pow<I: Int>(&self, b: I) -> ModP<M> {
		let mut b = b.as_i64();
		if b < 0 {
			b = b % (M::m() - 1) as i64 + M::m() as i64 - 1;
		}
		let mut res = ModP::new(1);
		let mut a = *self;
		while b > 0 {
			if (b & 1) > 0 { res *= a; }
			a *= a;
			b >>= 1;
		}
		res
	}
	pub fn inv(&self) -> ModP<M> {
		self.pow(M::m() as u64 - 2)
	}
}

impl<'a, M: Mod> Add for &'a ModP<M> {
	type Output = ModP<M>;
	fn add(self, a: &ModP<M>) -> ModP<M> {
		let v = self.0 + a.0;
		if v >= M::m() { ModP::new(v - M::m()) } else { ModP::new(v) }
	}
}

impl<'a, M: Mod> Sub for &'a ModP<M> {
	type Output = ModP<M>;
	fn sub(self, a: &ModP<M>) -> ModP<M> {
		if self.0 < a.0 { ModP::new(M::m() - a.0 + self.0) } else { ModP::new(self.0 - a.0 ) }
	}
}

impl<'a, M: Mod> Mul for &'a ModP<M> {
	type Output = ModP<M>;
	fn mul(self, a: &ModP<M>) -> ModP<M> {
		ModP::new(((self.0 as u64 * a.0 as u64) % M::m() as u64) as u32)
	}
}

impl<'a, M: Mod> Div for &'a ModP<M> {
	type Output = ModP<M>;
	fn div(self, a: &ModP<M>) -> ModP<M> {
		self * a.inv()
	}
}

impl<'a, M: Mod> Neg for &'a ModP<M> {
	type Output = ModP<M>;
	fn neg(self) -> ModP<M> {
		ModP::new(if self.0 == 0 { 0 } else { M::m() - self.0 })
	}
}

impl<M: Mod> Neg for ModP<M> {
	type Output = ModP<M>;
	fn neg(self) -> ModP<M> {
		(&self).neg()
	}
}

macro_rules! impl_all {
	($t:ident$(<$($g:ident),*>)*; $Op:ident:$op:ident:$Opa:ident:$opa:ident) => {
		impl<$($($g),*)*> $Op for $t$(<$($g),*>)* where for<'b> &'b $t$(<$($g),*>)*: $Op<Output = $t$(<$($g),*>)*> {
			type Output = $t$(<$($g),*>)*;
			fn $op(self, a: $t$(<$($g),*>)*) -> $t$(<$($g),*>)* { (&self).$op(&a) }
		}
		impl<'a, $($($g),*)*> $Op<&'a $t$(<$($g),*>)*> for $t$(<$($g),*>)* where for<'b> &'b $t$(<$($g),*>)*: $Op<Output = $t$(<$($g),*>)*> {
			type Output = $t$(<$($g),*>)*;
			fn $op(self, a: &$t$(<$($g),*>)*) -> $t$(<$($g),*>)* { (&self).$op(&a) }
		}
		impl<'a, $($($g),*)*> $Op<$t$(<$($g),*>)*> for &'a $t$(<$($g),*>)* where for<'b> &'b $t$(<$($g),*>)*: $Op<Output = $t$(<$($g),*>)*> {
			type Output = $t$(<$($g),*>)*;
			fn $op(self, a: $t$(<$($g),*>)*) -> $t$(<$($g),*>)* { (&self).$op(&a) }
		}
		impl<$($($g),*)*> $Opa for $t$(<$($g),*>)* where for<'b> &'b $t$(<$($g),*>)*: $Op<Output = $t$(<$($g),*>)*> {
			fn $opa(&mut self, a: $t$(<$($g),*>)*) { *self = (&*self).$op(&a) }
		}
	}
}

impl_all!(ModP<M>; Add:add:AddAssign:add_assign);
impl_all!(ModP<M>; Sub:sub:SubAssign:sub_assign);
impl_all!(ModP<M>; Mul:mul:MulAssign:mul_assign);
impl_all!(ModP<M>; Div:div:DivAssign:div_assign);

#[macro_export]
macro_rules! define_mod {
	($name:ident; $e:expr) => {
		#[derive(Clone, Copy, Default, Hash, PartialEq, PartialOrd, Eq, Ord)]
		pub struct _Mod;
		pub type $name = $crate::ModP<_Mod>;
		impl $crate::Mod for _Mod {
			fn m() -> u32 { $e }
		}
	}
}

impl<M: Mod, I: Int> From<I> for ModP<M> {
	/// Assume 0 <= a < m.
	fn from(a: I) -> ModP<M> { ModP::new(a) }
}


fn run() {
	let (N, M) = read!(usize, usize);
	let cs = read!([char]; N);
	let mut dp = mat![P::new(0); N; M];
	define_mod!(P; 1_000_000_007);
	dp[0][0] = P::new(1);
	for i in 0..N {
		for j in 0..M {
			if i + 1 < N && cs[i + 1][j] == '.' {
				dp[i + 1][j] += dp[i][j];
			}
			if j + 1 < M && cs[i][j + 1] == '.' {
				dp[i][j + 1] += dp[i][j];
			}
		}
	}
	println!("{}", dp[N - 1][M - 1]);
}


Measured memory_bytes: 16764