#![allow(unused_macros)]
#![allow(dead_code)]
#![allow(unused_imports)]

use itertools::Itertools;

const U_INF: usize = 1 << 60;
const I_INF: isize = 1 << 60;

fn main() {
    let mut sc = Scanner::new();
    let n = sc.next_usize();
    let m = sc.next_usize();

    if m.max(n) - m.min(n) > 1 {
        println!("0");
    } else {
        let mut ans = ModInt::new(1);
        for i in 1..=n {
            ans *= ModInt::new(i as isize);
        }
        for i in 1..=m {
            ans *= ModInt::new(i as isize);
        }

        if n == m {
            ans *= ModInt::new(2);
        }

        println!("{}", ans);
    }
}

pub const MOD: isize = 1000000007;
// pub const MOD: isize = 998244353;

/// 常に設定したModを取り続ける正整数型
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct ModInt {
    /// 保持する値
    value: isize,
}

impl ModInt {
    /// isizeを受け取り、ModIntに変換する
    pub fn new(n: isize) -> Self {
        let mut value = n % MOD;
        if value < 0 {
            value += MOD;
        }
        Self { value }
    }

    /// べき乗計算関数
    /// 二分累乗法を用いるため、計算量はO(log n)
    pub fn pow(self, n: usize) -> Self {
        if n == 0 {
            1.into()
        } else if n == 1 {
            self
        } else if n % 2 == 0 {
            (self * 2.into()).pow(n / 2)
        } else {
            self * self.pow(n - 1)
        }
    }

    /// 逆元を返す
    /// フェルマーの小定理より、べき乗を用いて計算するため、計算量はO(log MOD)
    pub fn inv(self) -> Self {
        self.pow((MOD - 2) as usize)
    }
}

impl std::fmt::Display for ModInt {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.value)
    }
}

impl From<usize> for ModInt {
    fn from(n: usize) -> Self {
        Self::new(n as isize)
    }
}

impl From<u64> for ModInt {
    fn from(n: u64) -> Self {
        Self::new(n as isize)
    }
}

impl From<u32> for ModInt {
    fn from(n: u32) -> Self {
        Self::new(n as isize)
    }
}

impl From<u16> for ModInt {
    fn from(n: u16) -> Self {
        Self::new(n as isize)
    }
}

impl From<u8> for ModInt {
    fn from(n: u8) -> Self {
        Self::new(n as isize)
    }
}

impl From<isize> for ModInt {
    fn from(n: isize) -> Self {
        Self::new(n)
    }
}

impl From<i64> for ModInt {
    fn from(n: i64) -> Self {
        Self::new(n as isize)
    }
}

impl From<i32> for ModInt {
    fn from(n: i32) -> Self {
        Self::new(n as isize)
    }
}

impl From<i16> for ModInt {
    fn from(n: i16) -> Self {
        Self::new(n as isize)
    }
}

impl From<i8> for ModInt {
    fn from(n: i8) -> Self {
        Self::new(n as isize)
    }
}

impl std::ops::Add for ModInt {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        let mut tmp = self.value + rhs.value;
        if tmp >= MOD {
            tmp %= MOD;
        }

        Self { value: tmp }
    }
}

impl std::ops::AddAssign for ModInt {
    fn add_assign(&mut self, rhs: Self) {
        *self = *self + rhs
    }
}

impl std::ops::Sub for ModInt {
    type Output = ModInt;

    fn sub(self, rhs: Self) -> Self::Output {
        let mut tmp = self.value;
        if tmp < rhs.value {
            tmp += MOD;
        }
        tmp -= rhs.value;
        if tmp >= MOD {
            tmp %= MOD;
        }

        Self { value: tmp }
    }
}

impl std::ops::SubAssign for ModInt {
    fn sub_assign(&mut self, rhs: Self) {
        *self = *self - rhs;
    }
}

impl std::ops::Mul for ModInt {
    type Output = ModInt;

    fn mul(self, rhs: Self) -> Self::Output {
        let mut tmp = self.value * rhs.value;
        if tmp >= MOD {
            tmp %= MOD;
        }

        Self { value: tmp }
    }
}

impl std::ops::MulAssign for ModInt {
    fn mul_assign(&mut self, rhs: Self) {
        *self = *self * rhs;
    }
}

impl std::ops::Div for ModInt {
    type Output = ModInt;

    fn div(self, rhs: Self) -> Self::Output {
        self * rhs.inv()
    }
}

impl std::ops::DivAssign for ModInt {
    fn div_assign(&mut self, rhs: Self) {
        *self = *self / rhs;
    }
}

pub struct Scanner {
    buf: std::collections::VecDeque<String>,
}

impl Scanner {
    pub fn new() -> Self {
        Self {
            buf: std::collections::VecDeque::new(),
        }
    }

    fn scan_line(&mut self) {
        let mut flag = 0;
        while self.buf.is_empty() {
            let mut s = String::new();
            std::io::stdin().read_line(&mut s).unwrap();
            let mut iter = s.split_whitespace().peekable();
            if iter.peek().is_none() {
                if flag >= 5 {
                    panic!("There is no input!");
                }
                flag += 1;
                continue;
            }

            for si in iter {
                self.buf.push_back(si.to_string());
            }
        }
    }

    pub fn next<T: std::str::FromStr>(&mut self) -> T {
        self.scan_line();
        self.buf
            .pop_front()
            .unwrap()
            .parse()
            .unwrap_or_else(|_| panic!("Couldn't parse!"))
    }

    pub fn next_usize(&mut self) -> usize {
        self.next()
    }

    pub fn next_isize(&mut self) -> isize {
        self.next()
    }

    pub fn next_chars(&mut self) -> Vec<char> {
        self.next::<String>().chars().collect()
    }

    pub fn next_string(&mut self) -> String {
        self.next()
    }

    pub fn next_char(&mut self) -> char {
        self.next()
    }

    pub fn next_float(&mut self) -> f64 {
        self.next()
    }
}


Measured memory_bytes: 2092